diff --git a/source/ona/kym.zig b/source/ona/kym.zig index 1b424e4..f3f224e 100644 --- a/source/ona/kym.zig +++ b/source/ona/kym.zig @@ -1,7 +1,5 @@ const Ast = @import("./kym/Ast.zig"); -const Table = @import("./kym/Table.zig"); - const coral = @import("coral"); const file = @import("./file.zig"); @@ -786,6 +784,101 @@ pub const RuntimeEnv = struct { const SymbolSet = coral.map.StringTable([:0]coral.io.Byte); + const Table = struct { + associative: RefTable, + contiguous: RefList, + + fn typeinfo_destruct(method: Typeinfo.Method) void { + const table = @as(*Table, @ptrCast(@alignCast(method.userdata.ptr))); + + { + var field_iterable = table.associative.as_iterable(); + + while (field_iterable.next()) |entry| { + method.env.discard(entry.key); + method.env.discard(entry.value); + } + } + + table.associative.free(); + + while (table.contiguous.pop()) |value| { + if (value) |ref| { + method.env.discard(ref); + } + } + + table.contiguous.free(); + } + + fn typeinfo_get(method: Typeinfo.Method, index: *const RuntimeRef) RuntimeError!?*RuntimeRef { + const table = @as(*Table, @ptrCast(@alignCast(method.userdata.ptr))); + const acquired_index = try method.env.acquire(index); + + defer method.env.discard(acquired_index); + + if (acquired_index.is_fixed()) |fixed| { + if (fixed < 0) { + // TODO: Negative indexing. + unreachable; + } + + if (fixed < table.contiguous.values.len) { + return method.env.acquire(table.contiguous.values[@intCast(fixed)] orelse return null); + } + } + + if (table.associative.lookup(acquired_index)) |value_ref| { + return method.env.acquire(value_ref); + } + + return null; + } + + fn typeinfo_set(method: Typeinfo.Method, index: *const RuntimeRef, value: ?*const RuntimeRef) RuntimeError!void { + const table = @as(*Table, @ptrCast(@alignCast(method.userdata.ptr))); + const acquired_index = try method.env.acquire(index); + + errdefer method.env.discard(acquired_index); + + if (acquired_index.is_fixed()) |fixed| { + if (fixed < 0) { + // TODO: Negative indexing. + unreachable; + } + + if (fixed < table.contiguous.values.len) { + const maybe_replacing = &table.contiguous.values[@intCast(fixed)]; + + if (maybe_replacing.*) |replacing| { + method.env.discard(replacing); + } + + maybe_replacing.* = if (value) |ref| try method.env.acquire(ref) else null; + + return; + } + } + + const acquired_value = try method.env.acquire(value orelse { + if (table.associative.remove(acquired_index)) |removed| { + method.env.discard(removed.key); + method.env.discard(removed.value); + } + + return; + }); + + errdefer method.env.discard(acquired_value); + + if (try table.associative.replace(acquired_index, acquired_value)) |replaced| { + method.env.discard(replaced.key); + method.env.discard(replaced.value); + } + } + + }; + pub fn acquire(self: *RuntimeEnv, value: *const RuntimeRef) RuntimeError!*RuntimeRef { const object = value.object(); @@ -1031,8 +1124,27 @@ pub const RuntimeEnv = struct { } pub fn new_table(self: *RuntimeEnv) RuntimeError!*RuntimeRef { - // TODO: Unroll this call logic into the environment. - return Table.new(self); + var table = Table{ + .associative = RefTable.make(self.allocator, .{}), + .contiguous = RefList.make(self.allocator), + }; + + errdefer { + table.associative.free(); + table.contiguous.free(); + } + + const newed = try self.new_dynamic(&.{ + .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 { diff --git a/source/ona/kym/Table.zig b/source/ona/kym/Table.zig deleted file mode 100644 index c2d54e4..0000000 --- a/source/ona/kym/Table.zig +++ /dev/null @@ -1,133 +0,0 @@ -const coral = @import("coral"); - -const kym = @import("../kym.zig"); - -associative: AssociativeTable, -contiguous: ContiguousList, - -const AssociativeTable = coral.map.Table(*kym.RuntimeRef, *kym.RuntimeRef, struct { - pub fn hash(key: *kym.RuntimeRef) usize { - return key.hash(); - } - - pub fn equals(key_a: *kym.RuntimeRef, key_b: *kym.RuntimeRef) bool { - return key_a.equals(key_b); - } -}); - -const ContiguousList = coral.list.Stack(?*kym.RuntimeRef); - -const Self = @This(); - -pub fn new(env: *kym.RuntimeEnv) kym.RuntimeError!*kym.RuntimeRef { - var self = Self{ - .associative = AssociativeTable.make(env.allocator, .{}), - .contiguous = ContiguousList.make(env.allocator), - }; - - errdefer { - self.associative.free(); - self.contiguous.free(); - } - - const table = try env.new_dynamic(&.{ - .name = "table", - .size = @sizeOf(Self), - .destruct = typeinfo_destruct, - .get = typeinfo_get, - .set = typeinfo_set, - }); - - coral.io.copy(env.unbox_dynamic(table) catch unreachable, coral.io.bytes_of(&self)); - - return table; -} - -fn typeinfo_destruct(method: kym.Typeinfo.Method) void { - const table = @as(*Self, @ptrCast(@alignCast(method.userdata.ptr))); - - { - var field_iterable = table.associative.as_iterable(); - - while (field_iterable.next()) |entry| { - method.env.discard(entry.key); - method.env.discard(entry.value); - } - } - - table.associative.free(); - - while (table.contiguous.pop()) |value| { - if (value) |ref| { - method.env.discard(ref); - } - } - - table.contiguous.free(); -} - -fn typeinfo_get(method: kym.Typeinfo.Method, index: *const kym.RuntimeRef) kym.RuntimeError!?*kym.RuntimeRef { - const table = @as(*Self, @ptrCast(@alignCast(method.userdata.ptr))); - const acquired_index = try method.env.acquire(index); - - defer method.env.discard(acquired_index); - - if (acquired_index.is_fixed()) |fixed| { - if (fixed < 0) { - // TODO: Negative indexing. - unreachable; - } - - if (fixed < table.contiguous.values.len) { - return method.env.acquire(table.contiguous.values[@intCast(fixed)] orelse return null); - } - } - - if (table.associative.lookup(acquired_index)) |value_ref| { - return method.env.acquire(value_ref); - } - - return null; -} - -fn typeinfo_set(method: kym.Typeinfo.Method, index: *const kym.RuntimeRef, value: ?*const kym.RuntimeRef) kym.RuntimeError!void { - const table = @as(*Self, @ptrCast(@alignCast(method.userdata.ptr))); - const acquired_index = try method.env.acquire(index); - - errdefer method.env.discard(acquired_index); - - if (acquired_index.is_fixed()) |fixed| { - if (fixed < 0) { - // TODO: Negative indexing. - unreachable; - } - - if (fixed < table.contiguous.values.len) { - const maybe_replacing = &table.contiguous.values[@intCast(fixed)]; - - if (maybe_replacing.*) |replacing| { - method.env.discard(replacing); - } - - maybe_replacing.* = if (value) |ref| try method.env.acquire(ref) else null; - - return; - } - } - - const acquired_value = try method.env.acquire(value orelse { - if (table.associative.remove(acquired_index)) |removed| { - method.env.discard(removed.key); - method.env.discard(removed.value); - } - - return; - }); - - errdefer method.env.discard(acquired_value); - - if (try table.associative.replace(acquired_index, acquired_value)) |replaced| { - method.env.discard(replaced.key); - method.env.discard(replaced.value); - } -}