92 lines
2.4 KiB
Zig
92 lines
2.4 KiB
Zig
const coral = @import("coral");
|
|
|
|
const kym = @import("../kym.zig");
|
|
|
|
fields: FieldTable,
|
|
|
|
const FieldTable = coral.map.StringTable(struct {
|
|
key_ref: ?*kym.RuntimeRef,
|
|
value_ref: ?*kym.RuntimeRef,
|
|
});
|
|
|
|
const Self = @This();
|
|
|
|
pub fn new(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef {
|
|
var self = Self{
|
|
.fields = FieldTable.make(env.allocator),
|
|
};
|
|
|
|
errdefer {
|
|
self.fields.free();
|
|
}
|
|
|
|
return try env.new_dynamic(coral.io.bytes_of(&self), &typeinfo);
|
|
}
|
|
|
|
pub const typeinfo = kym.Typeinfo{
|
|
.name = "table",
|
|
.clean = typeinfo_clean,
|
|
.get = typeinfo_get,
|
|
.set = typeinfo_set,
|
|
};
|
|
|
|
fn typeinfo_clean(env: *kym.RuntimeEnv, userdata: []coral.io.Byte) void {
|
|
const table = @as(*Self, @ptrCast(@alignCast(userdata.ptr)));
|
|
|
|
{
|
|
var field_iterable = table.fields.as_iterable();
|
|
|
|
while (field_iterable.next()) |entry| {
|
|
env.discard(entry.value.key_ref);
|
|
env.discard(entry.value.value_ref);
|
|
}
|
|
}
|
|
|
|
table.fields.free();
|
|
}
|
|
|
|
fn typeinfo_get(context: kym.IndexContext) kym.RuntimeError!?*kym.RuntimeRef {
|
|
const table = @as(*Self, @ptrCast(@alignCast(context.userdata.ptr)));
|
|
|
|
return switch (context.env.unbox(context.index_ref)) {
|
|
.string => |string| context.env.acquire((table.fields.lookup(string) orelse return null).value_ref),
|
|
// TODO: Implement number indices in tables.
|
|
.number => |_| unreachable,
|
|
else => context.env.raise(error.TypeMismatch, "table objects may only be indexed with strings or numbers"),
|
|
};
|
|
}
|
|
|
|
fn typeinfo_set(context: kym.IndexContext, value_ref: ?*const kym.RuntimeRef) kym.RuntimeError!void {
|
|
const table = @as(*Self, @ptrCast(@alignCast(context.userdata.ptr)));
|
|
const acquired_value_ref = context.env.acquire(value_ref);
|
|
|
|
errdefer context.env.discard(acquired_value_ref);
|
|
|
|
switch (context.env.unbox(context.index_ref)) {
|
|
.string => |string| {
|
|
const acquired_index_ref = context.env.acquire(context.index_ref);
|
|
|
|
errdefer context.env.discard(acquired_index_ref);
|
|
|
|
var displaced_table_entry = if (acquired_value_ref) |ref| try table.fields.replace(string, .{
|
|
.key_ref = acquired_index_ref,
|
|
.value_ref = ref,
|
|
}) else table.fields.remove(string);
|
|
|
|
if (displaced_table_entry) |*entry| {
|
|
context.env.discard(entry.value.key_ref);
|
|
context.env.discard(entry.value.value_ref);
|
|
}
|
|
},
|
|
|
|
.number => |_| {
|
|
// TODO: Implement number indices in tables.
|
|
unreachable;
|
|
},
|
|
|
|
else => {
|
|
return context.env.raise(error.TypeMismatch, "table objects may only be indexed with strings or numbers");
|
|
},
|
|
}
|
|
}
|