From 7b4b827dc231659528c0f06834798f1e13de3493 Mon Sep 17 00:00:00 2001 From: kayomn Date: Sat, 22 Jul 2023 11:03:23 +0100 Subject: [PATCH] Refactor Kym runtime API --- source/ona/app.zig | 46 ++++---- source/ona/heap.zig | 10 +- source/ona/kym.zig | 231 +++++++++++++++++++++------------------ source/ona/kym/Chunk.zig | 225 ++++++++++++++++++-------------------- source/ona/ona.zig | 12 +- 5 files changed, 266 insertions(+), 258 deletions(-) diff --git a/source/ona/app.zig b/source/ona/app.zig index 2a22b06..bd4117e 100644 --- a/source/ona/app.zig +++ b/source/ona/app.zig @@ -17,25 +17,17 @@ pub const Manifest = struct { defer env.discard(manifest_ref); - const title_ref = try kym.get_field(env, manifest_ref, "title"); - - defer env.discard(title_ref); - - const title_string = switch (env.unbox(title_ref)) { - .string => |string| string, - else => "", - }; - const width = @as(u16, get: { const ref = try kym.get_field(env, manifest_ref, "width"); defer env.discard(ref); - // TODO: Add safety-checks to int cast. - break: get switch (env.unbox(ref)) { - .number => |number| @intFromFloat(number), - else => self.width, - }; + if (env.unbox(ref).expect_number()) |number| { + // TODO: Add safety-checks to int cast. + break: get @intFromFloat(number); + } + + break: get self.width; }); const height = @as(u16, get: { @@ -43,11 +35,12 @@ pub const Manifest = struct { defer env.discard(ref); - // TODO: Add safety-checks to int cast. - break: get switch (env.unbox(ref)) { - .number => |number| @intFromFloat(number), - else => self.height, - }; + if (env.unbox(ref).expect_number()) |number| { + // TODO: Add safety-checks to int cast. + break: get @intFromFloat(number); + } + + break: get self.height; }); const tick_rate = @as(f32, get: { @@ -55,13 +48,20 @@ pub const Manifest = struct { defer env.discard(ref); - break: get switch (env.unbox(ref)) { - .number => |number| @floatCast(number), - else => self.tick_rate, - }; + if (env.unbox(ref).expect_number()) |number| { + // TODO: Add safety-checks to int cast. + break: get @floatCast(number); + } + + break: get self.tick_rate; }); { + const title_ref = try kym.get_field(env, manifest_ref, "title"); + + defer env.discard(title_ref); + + const title_string = env.unbox(title_ref).expect_string() orelse ""; const limited_title_len = coral.math.min(title_string.len, self.title.len); coral.io.copy(&self.title, title_string[0 .. limited_title_len]); diff --git a/source/ona/heap.zig b/source/ona/heap.zig index b4ec97a..8639461 100644 --- a/source/ona/heap.zig +++ b/source/ona/heap.zig @@ -156,15 +156,15 @@ pub const allocator = coral.io.Allocator.bind(Context, &context, .{ pub fn trace_leaks() void { switch (builtin.mode) { .Debug, .ReleaseSafe => { - var current_allocation_info = context.allocation_info_head; + var current_node = context.head; - while (current_allocation_info) |allocation_info| : (current_allocation_info = allocation_info.next_info) { + while (current_node) |node| : (current_node = node.next) { std.debug.print("{d} byte leak at 0x{x} detected:\n", .{ - allocation_info.size, - @as(usize, allocation_info) + @sizeOf(AllocationNode), + node.size, + @intFromPtr(node) + @sizeOf(AllocationNode), }); - allocation_info.trace.dump(); + node.trace.dump(); } }, diff --git a/source/ona/kym.zig b/source/ona/kym.zig index d57ce67..016ffe9 100644 --- a/source/ona/kym.zig +++ b/source/ona/kym.zig @@ -10,17 +10,48 @@ const file = @import("./file.zig"); const tokens = @import("./kym/tokens.zig"); -pub const Args = []const ?*const RuntimeRef; +pub const Any = union (enum) { + nil, + boolean: bool, + number: Float, + string: []const coral.io.Byte, + dynamic: *DynamicObject, -pub const CallContext = struct { - env: *RuntimeEnv, - caller: ?*const RuntimeRef, - userdata: []coral.io.Byte, + pub fn expect_dynamic(self: Any) ?*DynamicObject { + return switch (self) { + .dynamic => |dynamic| dynamic, + else => null, + }; + } + + pub fn expect_number(self: Any) ?Float { + return switch (self) { + .number => |number| number, + else => null, + }; + } + + pub fn expect_string(self: Any) ?[]const coral.io.Byte { + return switch (self) { + .string => |string| string, + else => null, + }; + } }; +pub const Caller = coral.io.Generator(RuntimeError!?*RuntimeRef, *RuntimeEnv); + pub const DynamicObject = struct { userdata: []coral.io.Byte, typeinfo: *const Typeinfo, + + pub fn as_caller(self: *DynamicObject) Caller { + return Caller.bind(DynamicObject, self, DynamicObject.call); + } + + fn call(self: *DynamicObject, env: *RuntimeEnv) RuntimeError!?*RuntimeRef { + return self.typeinfo.call(env); + } }; pub const ErrorHandler = coral.io.Generator(void, ErrorInfo); @@ -54,7 +85,7 @@ pub const RuntimeEnv = struct { const FrameStack = coral.list.Stack(Frame); - const SyscallerTable = coral.map.StringTable(Syscaller); + const SyscallerTable = coral.map.StringTable(Caller); const RefStack = coral.list.Stack(?*RuntimeRef); @@ -72,7 +103,7 @@ pub const RuntimeEnv = struct { pub const Syscall = struct { name: []const coral.io.Byte, - caller: Syscaller, + caller: Caller, }; pub fn acquire(self: *RuntimeEnv, ref: ?*const RuntimeRef) ?*RuntimeRef { @@ -94,6 +125,30 @@ pub const RuntimeEnv = struct { } } + pub fn call( + self: *RuntimeEnv, + name: []const coral.io.Byte, + arg_count: u8, + caller: Caller, + ) RuntimeError!?*RuntimeRef { + try self.frames.push_one(.{ + .name = name, + .arg_count = arg_count, + .locals_top = self.local_refs.values.len, + }); + + defer { + const frame = self.frames.pop(); + + coral.debug.assert(frame != null); + + coral.debug.assert(self.local_refs.drop( + (self.local_refs.values.len - frame.?.locals_top) + frame.?.arg_count)); + } + + return caller.invoke(self); + } + pub fn discard(self: *RuntimeEnv, ref: ?*RuntimeRef) void { const key = @intFromPtr(ref orelse return); var ref_data = self.ref_values.remove(key) orelse unreachable; @@ -143,28 +198,13 @@ pub const RuntimeEnv = struct { }; } - var exe = Chunk.make(self); + var chunk = Chunk.make(self); - defer exe.free(); + defer chunk.free(); - try exe.compile_ast(ast); + try chunk.compile_ast(ast); - return try exe.execute(name); - } - - pub fn frame_pop(self: *RuntimeEnv) void { - const frame = self.frames.pop(); - - coral.debug.assert(frame != null); - coral.debug.assert(self.local_refs.drop((self.local_refs.values.len - frame.?.locals_top) + frame.?.arg_count)); - } - - pub fn frame_push(self: *RuntimeEnv, frame_name: []const coral.io.Byte, arg_count: u8) RuntimeError!void { - try self.frames.push_one(.{ - .name = frame_name, - .arg_count = arg_count, - .locals_top = self.local_refs.values.len, - }); + return self.call(name, 0, chunk.as_caller()); } pub fn free(self: *RuntimeEnv) void { @@ -172,41 +212,35 @@ pub const RuntimeEnv = struct { self.ref_values.free(); } - pub fn get_arg(self: *RuntimeEnv, index: usize) RuntimeError!?*const RuntimeRef { - const frame = self.frames.peek() orelse return self.raise(error.IllegalState, "stack underflow"); - - if (index >= frame.arg_count) { - return null; + pub fn get_local(self: *RuntimeEnv, local: u8) RuntimeError!?*RuntimeRef { + if (local >= self.local_refs.values.len) { + return self.raise(error.IllegalState, "out of bounds local get"); } - return self.local_refs.values[frame.locals_top - (1 + index)]; - } - - pub fn local_get(self: *RuntimeEnv, local: u8) ?*RuntimeRef { return self.local_refs.values[local]; } - pub fn local_pop(self: *RuntimeEnv) ?*RuntimeRef { - const ref = self.local_refs.pop(); - - coral.debug.assert(ref != null); - - return ref.?; + pub fn pop_local(self: *RuntimeEnv) RuntimeError!?*RuntimeRef { + return self.local_refs.pop() orelse self.raise(error.IllegalState, "stack underflow"); } - pub fn local_push_ref(self: *RuntimeEnv, ref: ?*RuntimeRef) RuntimeError!void { - return self.local_refs.push_one(self.acquire(ref)); - } - - pub fn local_push_boolean(self: *RuntimeEnv, boolean: bool) RuntimeError!void { + pub fn push_boolean(self: *RuntimeEnv, boolean: bool) RuntimeError!void { return self.local_refs.push_one(try self.new_boolean(boolean)); } - pub fn local_push_number(self: *RuntimeEnv, number: Float) RuntimeError!void { + pub fn push_number(self: *RuntimeEnv, number: Float) RuntimeError!void { return self.local_refs.push_one(try self.new_number(number)); } - pub fn local_set(self: *RuntimeEnv, local: u8, value: ?*RuntimeRef) void { + pub fn push_ref(self: *RuntimeEnv, ref: ?*RuntimeRef) RuntimeError!void { + return self.local_refs.push_one(self.acquire(ref)); + } + + pub fn set_local(self: *RuntimeEnv, local: u8, value: ?*RuntimeRef) RuntimeError!void { + if (local >= self.local_refs.values.len) { + return self.raise(error.IllegalState, "out of bounds local set"); + } + self.local_refs.values[local] = self.acquire(value); } @@ -277,50 +311,36 @@ pub const RuntimeEnv = struct { return error_value; } - pub fn syscaller(self: *RuntimeEnv, name: []const coral.io.Byte) RuntimeError!Syscaller { + pub fn syscaller(self: *RuntimeEnv, name: []const coral.io.Byte) RuntimeError!Caller { return self.syscallers.lookup(name) orelse self.raise(error.BadOperation, "attempt to call undefined syscall"); } - pub fn unbox(self: *RuntimeEnv, ref: ?*const RuntimeRef) Unboxed { - const ref_data = self.ref_values.lookup(@intFromPtr(ref orelse return .nil)); - - coral.debug.assert(ref_data != null); - - return switch (ref_data.?.object) { - .false => .{.boolean = false}, - .true => .{.boolean = true}, - .number => |number| .{.number = number}, - .string => |string| .{.string = string}, - .dynamic => |dynamic| .{.dynamic = dynamic}, - }; - } - - pub fn unbox_dynamic(self: *RuntimeEnv, ref: ?*const RuntimeRef) RuntimeError![]const coral.io.Byte { + pub fn unbox(self: *RuntimeEnv, ref: ?*const RuntimeRef) Any { if (ref) |live_ref| { const ref_data = self.ref_values.lookup(@intFromPtr(live_ref)); coral.debug.assert(ref_data != null); - if (ref_data.?.object == .dynamic) { - return ref_data.?.object.dynamic; - } + return switch (ref_data.?.object) { + .false => .{.boolean = false}, + .true => .{.boolean = true}, + .number => |number| .{.number = number}, + .string => |string| .{.string = string}, + .dynamic => |dynamic| .{.dynamic = dynamic}, + }; } - return self.raise(error.TypeMismatch, "expected dynamic"); + return .nil; } - pub fn unbox_string(self: *RuntimeEnv, ref: ?*const RuntimeRef) RuntimeError![]const coral.io.Byte { - if (ref) |live_ref| { - const ref_data = self.ref_values.lookup(@intFromPtr(live_ref)); + pub fn view_arg(self: *RuntimeEnv, index: usize) RuntimeError!?*const RuntimeRef { + const frame = self.frames.peek() orelse return self.raise(error.IllegalState, "stack underflow"); - coral.debug.assert(ref_data != null); - - if (ref_data.?.object == .string) { - return ref_data.?.object.string; - } + if (index >= frame.arg_count) { + return null; } - return self.raise(error.TypeMismatch, "expected string"); + return self.local_refs.values[frame.locals_top - (1 + index)]; } }; @@ -329,13 +349,10 @@ pub const RuntimeError = coral.io.AllocationError || error { TypeMismatch, BadOperation, BadSyntax, - Assertion, }; pub const RuntimeRef = opaque {}; -pub const Syscaller = coral.io.Generator(RuntimeError!?*RuntimeRef, *RuntimeEnv); - pub const TestContext = struct { env: *RuntimeEnv, userdata: []const coral.io.Byte, @@ -344,15 +361,15 @@ pub const TestContext = struct { pub const Typeinfo = struct { name: []const coral.io.Byte, - call: *const fn (context: CallContext) RuntimeError!?*RuntimeRef = default_call, + call: *const fn (env: *RuntimeEnv) RuntimeError!?*RuntimeRef = default_call, clean: *const fn (userdata: []coral.io.Byte) void = default_clean, get: *const fn (context: IndexContext) RuntimeError!?*RuntimeRef = default_get, set: *const fn (context: IndexContext, value: ?*const RuntimeRef) RuntimeError!void = default_set, test_difference: *const fn (context: TestContext) RuntimeError!Float = default_test_difference, test_equality: *const fn (context: TestContext) RuntimeError!bool = default_test_equality, - fn default_call(context: CallContext) RuntimeError!?*RuntimeRef { - return context.env.raise(error.TypeMismatch, "object is not callable"); + fn default_call(env: *RuntimeEnv) RuntimeError!?*RuntimeRef { + return env.raise(error.TypeMismatch, "object is not callable"); } fn default_clean(_: []coral.io.Byte) void { @@ -379,32 +396,11 @@ pub const Typeinfo = struct { } }; -pub const Unboxed = union (enum) { - nil, - boolean: bool, - number: Float, - string: []const coral.io.Byte, - dynamic: *const DynamicObject, - - pub fn expect_dynamic(self: Unboxed, env: *RuntimeEnv) RuntimeError!*const DynamicObject { - return switch (self) { - .dynamic => |dynamic| dynamic, - else => env.raise(error.TypeMismatch, "expected dynamic"), - }; - } -}; - -pub fn assert(env: *RuntimeEnv, condition: bool, message: []const coral.io.Byte) RuntimeError!void { - if (!condition) { - return env.raise(error.Assertion, message); - } -} - pub fn call( env: *RuntimeEnv, caller_ref: ?*const RuntimeRef, callable_ref: ?*const RuntimeRef, - arg_refs: Args, + arg_refs: []const ?*const RuntimeRef, ) RuntimeError!?*RuntimeRef { for (arg_refs) |arg_ref| { try env.local_push_ref(arg_ref); @@ -428,7 +424,7 @@ pub fn get( indexable_ref: ?*const RuntimeRef, index_ref: ?*const RuntimeRef, ) RuntimeError!?*RuntimeRef { - const dynamic = try env.unbox(indexable_ref).expect_dynamic(env); + const dynamic = try unbox_dynamic(env, indexable_ref); return dynamic.typeinfo.get(.{ .userdata = dynamic.userdata, @@ -437,7 +433,11 @@ pub fn get( }); } -pub fn get_field(env: *RuntimeEnv, indexable_ref: ?*const RuntimeRef, field_name: []const coral.io.Byte) RuntimeError!?*RuntimeRef { +pub fn get_field( + env: *RuntimeEnv, + indexable_ref: ?*const RuntimeRef, + field_name: []const coral.io.Byte, +) RuntimeError!?*RuntimeRef { const field_name_ref = try env.new_string(field_name); defer env.discard(field_name_ref); @@ -451,7 +451,7 @@ pub fn set( index_ref: ?*const RuntimeRef, value_ref: ?*const RuntimeRef, ) RuntimeError!void { - const dynamic = try env.unbox(indexable_ref).expect_dynamic(env); + const dynamic = try unbox_dynamic(env, indexable_ref); return dynamic.typeinfo.set(.{ .userdata = dynamic.userdata, @@ -460,7 +460,12 @@ pub fn set( }, value_ref); } -pub fn set_field(env: *RuntimeEnv, indexable_ref: ?*const RuntimeRef, field_name: []const coral.io.Byte, value_ref: ?*const RuntimeRef) RuntimeError!void { +pub fn set_field( + env: *RuntimeEnv, + indexable_ref: ?*const RuntimeRef, + field_name: []const coral.io.Byte, + value_ref: ?*const RuntimeRef, +) RuntimeError!void { const field_name_ref = try env.new_string(field_name); defer env.discard(field_name_ref); @@ -525,3 +530,11 @@ pub fn test_equality(env: *RuntimeEnv, lhs_ref: ?*const RuntimeRef, rhs_ref: ?*c }), }; } + +pub fn unbox_dynamic(env: *RuntimeEnv, ref: ?*const RuntimeRef) RuntimeError!*DynamicObject { + return env.unbox(ref).expect_dynamic() orelse env.raise(error.TypeMismatch, "expected dynamic object"); +} + +pub fn unbox_string(env: *RuntimeEnv, ref: ?*const RuntimeRef) RuntimeError![]const coral.io.Byte { + return env.unbox(ref).expect_string() orelse env.raise(error.TypeMismatch, "expected string object"); +} diff --git a/source/ona/kym/Chunk.zig b/source/ona/kym/Chunk.zig index c029e15..e06002c 100644 --- a/source/ona/kym/Chunk.zig +++ b/source/ona/kym/Chunk.zig @@ -206,6 +206,10 @@ pub fn append_opcode(self: *Self, opcode: Opcode) kym.RuntimeError!void { return self.opcodes.push_one(opcode); } +pub fn as_caller(self: *Self) kym.Caller { + return kym.Caller.bind(Self, self, execute); +} + pub fn compile_ast(self: *Self, ast: Ast) kym.RuntimeError!void { self.free(); @@ -253,250 +257,239 @@ pub fn declare_constant_string(self: *Self, constant: []const coral.io.Byte) kym return @intCast(tail); } -pub fn execute(self: *Self, name: []const coral.io.Byte) kym.RuntimeError!?*kym.RuntimeRef { - try self.env.frame_push(name, 0); - - defer self.env.frame_pop(); - +fn execute(self: *Self, env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef { for (self.opcodes.values) |opcode| { switch (opcode) { - .pop => self.env.discard(self.env.local_pop()), - .push_nil => try self.env.local_push_ref(null), - .push_true => try self.env.local_push_boolean(true), - .push_false => try self.env.local_push_boolean(false), - .push_const => |constant| try self.env.local_push_ref(self.constant_refs.values[constant]), + .pop => env.discard(try env.pop_local()), + .push_nil => try env.push_ref(null), + .push_true => try env.push_boolean(true), + .push_false => try env.push_boolean(false), + .push_const => |constant| try env.push_ref(self.constant_refs.values[constant]), .push_table => |field_count| { - const table_ref = try kym.new_table(self.env); + const table_ref = try kym.new_table(env); - defer self.env.discard(table_ref); + defer env.discard(table_ref); { - const dynamic = try self.env.unbox(table_ref).expect_dynamic(self.env); + const dynamic = try kym.unbox_dynamic(env, table_ref); var popped = @as(usize, 0); while (popped < field_count) : (popped += 1) { - const index_ref = self.env.local_pop(); - const value_ref = self.env.local_pop(); + const index_ref = try env.pop_local(); + + defer env.discard(index_ref); + + const value_ref = try env.pop_local(); + + defer env.discard(value_ref); try dynamic.typeinfo.set(.{ .userdata = dynamic.userdata, - .env = self.env, + .env = env, .index_ref = index_ref, }, value_ref); } } - try self.env.local_push_ref(table_ref); + try env.push_ref(table_ref); }, .push_local => |local| { - const ref = self.env.local_get(local); + const ref = try env.get_local(local); - defer self.env.discard(ref); + defer env.discard(ref); - try self.env.local_push_ref(ref); + try env.push_ref(ref); }, .set_local => |local| { - const ref = self.env.local_pop(); + const ref = try env.pop_local(); - defer self.env.discard(ref); + defer env.discard(ref); - self.env.local_set(local, ref); + try env.set_local(local, ref); }, .call => |arg_count| { - const callable_ref = self.env.local_pop(); + const result_ref = call: { + const callable_ref = try env.pop_local(); - defer self.env.discard(callable_ref); + defer env.discard(callable_ref); - try self.env.frame_push("", arg_count); + break: call try env.call("", arg_count, (try kym.unbox_dynamic(env, callable_ref)).as_caller()); + }; - defer self.env.frame_pop(); + defer env.discard(result_ref); - const dynamic = try self.env.unbox(callable_ref).expect_dynamic(self.env); - - const result_ref = try dynamic.typeinfo.call(.{ - .env = self.env, - .caller = null, - .userdata = dynamic.userdata, - }); - - defer self.env.discard(result_ref); - - try self.env.local_push_ref(result_ref); + try env.push_ref(result_ref); }, .syscall => |arg_count| { - const identifier_ref = self.env.local_pop(); + const result_ref = call: { + const identifier_ref = try env.pop_local(); - defer self.env.discard(identifier_ref); + defer env.discard(identifier_ref); - const identifier = try self.env.unbox_string(identifier_ref); + const identifier = try kym.unbox_string(env, identifier_ref); - try self.env.frame_push(identifier, arg_count); + break: call try env.call(identifier, arg_count, try env.syscaller(identifier)); + }; - errdefer self.env.frame_pop(); + defer env.discard(result_ref); - const result_ref = try (try self.env.syscaller(identifier)).invoke(self.env); - - defer self.env.discard(result_ref); - - self.env.frame_pop(); - - try self.env.local_push_ref(result_ref); + try env.push_ref(result_ref); }, - .neg => try self.env.local_push_number(switch (self.env.unbox(self.env.local_pop())) { + .neg => try env.push_number(switch (env.unbox(try env.pop_local())) { .number => |number| -number, - else => return self.env.raise(error.TypeMismatch, "object is not scalar negatable"), + else => return env.raise(error.TypeMismatch, "object is not scalar negatable"), }), - .not => try self.env.local_push_boolean(switch (self.env.unbox(self.env.local_pop())) { + .not => try env.push_boolean(switch (env.unbox(try env.pop_local())) { .boolean => |boolean| !boolean, - else => return self.env.raise(error.TypeMismatch, "object is not boolean negatable"), + else => return env.raise(error.TypeMismatch, "object is not boolean negatable"), }), .add => { - const rhs_ref = self.env.local_pop(); + const rhs_ref = try env.pop_local(); - defer self.env.discard(rhs_ref); + defer env.discard(rhs_ref); - const lhs_ref = self.env.local_pop(); + const lhs_ref = try env.pop_local(); - defer self.env.discard(lhs_ref); + defer env.discard(lhs_ref); - try self.env.local_push_ref(switch (self.env.unbox(lhs_ref)) { - .number => |lhs_number| switch (self.env.unbox(rhs_ref)) { - .number => |rhs_number| try self.env.new_number(lhs_number + rhs_number), - else => return self.env.raise(error.TypeMismatch, "right-hand object is not addable"), + try env.push_ref(try switch (env.unbox(lhs_ref)) { + .number => |lhs_number| switch (env.unbox(rhs_ref)) { + .number => |rhs_number| env.new_number(lhs_number + rhs_number), + else => return env.raise(error.TypeMismatch, "right-hand object is not addable"), }, - else => return self.env.raise(error.TypeMismatch, "left-hand object is not addable"), + else => return env.raise(error.TypeMismatch, "left-hand object is not addable"), }); }, .sub => { - const rhs_ref = self.env.local_pop(); + const rhs_ref = try env.pop_local(); - defer self.env.discard(rhs_ref); + defer env.discard(rhs_ref); - const lhs_ref = self.env.local_pop(); + const lhs_ref = try env.pop_local(); - defer self.env.discard(lhs_ref); + defer env.discard(lhs_ref); - try self.env.local_push_ref(switch (self.env.unbox(lhs_ref)) { - .number => |lhs_number| switch (self.env.unbox(rhs_ref)) { - .number => |rhs_number| try self.env.new_number(lhs_number - rhs_number), - else => return self.env.raise(error.TypeMismatch, "right-hand object is not subtractable"), + try env.push_ref(try switch (env.unbox(lhs_ref)) { + .number => |lhs_number| switch (env.unbox(rhs_ref)) { + .number => |rhs_number| env.new_number(lhs_number - rhs_number), + else => return env.raise(error.TypeMismatch, "right-hand object is not subtractable"), }, - else => return self.env.raise(error.TypeMismatch, "left-hand object is not subtractable"), + else => return env.raise(error.TypeMismatch, "left-hand object is not subtractable"), }); }, .mul => { - const rhs_ref = self.env.local_pop(); + const rhs_ref = try env.pop_local(); - defer self.env.discard(rhs_ref); + defer env.discard(rhs_ref); - const lhs_ref = self.env.local_pop(); + const lhs_ref = try env.pop_local(); - defer self.env.discard(lhs_ref); + defer env.discard(lhs_ref); - try self.env.local_push_ref(switch (self.env.unbox(lhs_ref)) { - .number => |lhs_number| switch (self.env.unbox(rhs_ref)) { - .number => |rhs_number| try self.env.new_number(lhs_number * rhs_number), - else => return self.env.raise(error.TypeMismatch, "right-hand object is not multiplyable"), + try env.push_ref(try switch (env.unbox(lhs_ref)) { + .number => |lhs_number| switch (env.unbox(rhs_ref)) { + .number => |rhs_number| env.new_number(lhs_number * rhs_number), + else => return env.raise(error.TypeMismatch, "right-hand object is not multiplyable"), }, - else => return self.env.raise(error.TypeMismatch, "left-hand object is not multiplyable"), + else => return env.raise(error.TypeMismatch, "left-hand object is not multiplyable"), }); }, .div => { - const rhs_ref = self.env.local_pop(); + const rhs_ref = try env.pop_local(); - defer self.env.discard(rhs_ref); + defer env.discard(rhs_ref); - const lhs_ref = self.env.local_pop(); + const lhs_ref = try env.pop_local(); - defer self.env.discard(lhs_ref); + defer env.discard(lhs_ref); - try self.env.local_push_ref(switch (self.env.unbox(lhs_ref)) { - .number => |lhs_number| switch (self.env.unbox(rhs_ref)) { - .number => |rhs_number| try self.env.new_number(lhs_number / rhs_number), - else => return self.env.raise(error.TypeMismatch, "right-hand object is not divisable"), + try env.push_ref(try switch (env.unbox(lhs_ref)) { + .number => |lhs_number| switch (env.unbox(rhs_ref)) { + .number => |rhs_number| env.new_number(lhs_number / rhs_number), + else => return env.raise(error.TypeMismatch, "right-hand object is not divisable"), }, - else => return self.env.raise(error.TypeMismatch, "left-hand object is not divisable"), + else => return env.raise(error.TypeMismatch, "left-hand object is not divisable"), }); }, .eql => { - const rhs_ref = self.env.local_pop(); + const rhs_ref = try env.pop_local(); - defer self.env.discard(rhs_ref); + defer env.discard(rhs_ref); - const lhs_ref = self.env.local_pop(); + const lhs_ref = try env.pop_local(); - defer self.env.discard(lhs_ref); + defer env.discard(lhs_ref); - try self.env.local_push_boolean(try kym.test_equality(self.env, lhs_ref, rhs_ref)); + try env.push_boolean(try kym.test_equality(env, lhs_ref, rhs_ref)); }, .cgt => { - const rhs_ref = self.env.local_pop(); + const rhs_ref = try env.pop_local(); - defer self.env.discard(rhs_ref); + defer env.discard(rhs_ref); - const lhs_ref = self.env.local_pop(); + const lhs_ref = try env.pop_local(); - defer self.env.discard(lhs_ref); + defer env.discard(lhs_ref); - try self.env.local_push_boolean(try kym.test_difference(self.env, lhs_ref, rhs_ref) > 0); + try env.push_boolean(try kym.test_difference(env, lhs_ref, rhs_ref) > 0); }, .clt => { - const rhs_ref = self.env.local_pop(); + const rhs_ref = try env.pop_local(); - defer self.env.discard(rhs_ref); + defer env.discard(rhs_ref); - const lhs_ref = self.env.local_pop(); + const lhs_ref = try env.pop_local(); - defer self.env.discard(lhs_ref); + defer env.discard(lhs_ref); - try self.env.local_push_boolean(try kym.test_difference(self.env, lhs_ref, rhs_ref) < 0); + try env.push_boolean(try kym.test_difference(env, lhs_ref, rhs_ref) < 0); }, .cge => { - const rhs_ref = self.env.local_pop(); + const rhs_ref = try env.pop_local(); - defer self.env.discard(rhs_ref); + defer env.discard(rhs_ref); - const lhs_ref = self.env.local_pop(); + const lhs_ref = try env.pop_local(); - defer self.env.discard(lhs_ref); + defer env.discard(lhs_ref); - try self.env.local_push_boolean(try kym.test_difference(self.env, lhs_ref, rhs_ref) >= 0); + try env.push_boolean(try kym.test_difference(env, lhs_ref, rhs_ref) >= 0); }, .cle => { - const rhs_ref = self.env.local_pop(); + const rhs_ref = try env.pop_local(); - defer self.env.discard(rhs_ref); + defer env.discard(rhs_ref); - const lhs_ref = self.env.local_pop(); + const lhs_ref = try env.pop_local(); - defer self.env.discard(lhs_ref); + defer env.discard(lhs_ref); - try self.env.local_push_boolean(try kym.test_difference(self.env, lhs_ref, rhs_ref) <= 0); + try env.push_boolean(try kym.test_difference(env, lhs_ref, rhs_ref) <= 0); }, } } - return self.env.local_pop(); + return env.pop_local(); } pub fn free(self: *Self) void { diff --git a/source/ona/ona.zig b/source/ona/ona.zig index 18facc5..a0573d1 100644 --- a/source/ona/ona.zig +++ b/source/ona/ona.zig @@ -21,19 +21,19 @@ fn kym_handle_errors(info: kym.ErrorInfo) void { } fn kym_log_info(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef { - app.log_info(try env.unbox_string(try env.get_arg(0))); + app.log_info(try kym.unbox_string(env, try env.view_arg(0))); return null; } fn kym_log_warn(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef { - app.log_warn(try env.unbox_string(try env.get_arg(0))); + app.log_warn(try kym.unbox_string(env, try env.view_arg(0))); return null; } fn kym_log_fail(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef { - app.log_fail(try env.unbox_string(try env.get_arg(0))); + app.log_fail(try kym.unbox_string(env, try env.view_arg(0))); return null; } @@ -43,6 +43,8 @@ fn last_sdl_error() [:0]const u8 { } pub fn run_app(file_access: file.Access) void { + defer heap.trace_leaks(); + if (ext.SDL_Init(ext.SDL_INIT_EVERYTHING) != 0) { return app.log_fail(last_sdl_error()); } @@ -58,11 +60,11 @@ pub fn run_app(file_access: file.Access) void { script_env.bind_syscalls(&.{ .{ .name = "log_info", - .caller = kym.Syscaller.from(kym_log_info), + .caller = kym.Caller.from(kym_log_info), }, .{ .name = "log_fail", - .caller = kym.Syscaller.from(kym_log_fail), + .caller = kym.Caller.from(kym_log_fail), }, }) catch { return app.log_fail("failed to initialize script runtime");