ona/source/ona/kym/State.zig
kayomn dc674ae2c3
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Add local variables to Kym
2023-07-12 01:51:32 +01:00

153 lines
3.4 KiB
Zig

const coral = @import("coral");
allocator: coral.io.Allocator,
interned: SymbolTable,
globals: Object,
values: DataStack,
frames: CallStack,
pub const Float = f64;
const CallStack = coral.list.Stack(struct {
callable: *Object,
opcode_index: usize,
stack_index: usize,
});
const DataStack = coral.list.Stack(Variant);
pub const Object = struct {
ref_count: usize,
userdata: []coral.io.Byte,
userinfo: *const anyopaque,
};
pub const PopError = error {
StackOverflow,
};
const Self = @This();
const SymbolTable = coral.map.Table([]const coral.io.Byte, *Object, coral.map.string_table_traits);
pub const Variant = union (enum) {
nil,
true,
false,
number: Float,
object: *Object,
pub fn equals(self: Variant, other: Variant) bool {
return switch (self) {
.nil => other == .nil,
.true => other == .true,
.false => other == .false,
.number => |number| switch (other) {
.number => |other_number| number == other_number,
else => false,
},
.object => |object| switch (other) {
.object => |other_object| object == other_object,
else => false,
},
};
}
};
pub fn acquire_instance(_: *Self, object: *Object) *Object {
// TODO: safety-check object belongs to state.
object.ref_count += 1;
return object;
}
pub fn acquire_interned(self: *Self, userdata: []const u8, userinfo: *const anyopaque) coral.io.AllocationError!*Object {
// TODO: Include userinfo in matching lookup.
if (self.interned.lookup(userdata)) |object| {
return self.acquire_instance(object);
} else {
const data_object = try self.acquire_new(userdata, userinfo);
errdefer self.release(data_object);
coral.debug.assert(try self.interned.insert(data_object.userdata, data_object));
return data_object;
}
}
pub fn acquire_new(self: *Self, userdata: []const u8, userinfo: *const anyopaque) coral.io.AllocationError!*Object {
const allocated_userdata = try coral.io.allocate_copy(self.allocator, userdata);
errdefer self.allocator.deallocate(allocated_userdata);
const allocated_object = try coral.io.allocate_one(self.allocator, Object{
.ref_count = 1,
.userdata = allocated_userdata,
.userinfo = userinfo,
});
errdefer self.allocator.deallocate(allocated_object);
return allocated_object;
}
pub fn free(self: *Self) void {
self.values.free();
self.frames.free();
self.interned.free();
}
pub fn get_value(self: *Self, tail_index: usize) Variant {
if (tail_index >= self.values.values.len) {
return .nil;
}
return self.values.values[self.values.values.len - (1 + tail_index)];
}
pub fn make(allocator: coral.io.Allocator) Self {
return .{
.values = DataStack.make(allocator),
.frames = CallStack.make(allocator),
.interned = SymbolTable.make(allocator),
.allocator = allocator,
.globals = .{
.ref_count = 0,
.userdata = &.{},
.userinfo = &.{},
},
};
}
pub fn pop_value(self: *Self) PopError!Variant {
return self.values.pop() orelse error.StackOverflow;
}
pub fn push_value(self: *Self, value: Variant) coral.io.AllocationError!void {
return self.values.push_one(value);
}
pub fn release(self: *Self, object: *Object) void {
coral.debug.assert(object.ref_count != 0);
object.ref_count -= 1;
if (object.ref_count == 0) {
self.allocator.deallocate(object);
}
}
pub fn set_value(self: *Self, tail_index: usize, value: Variant) bool {
if (tail_index >= self.values.values.len) {
return false;
}
self.values.values[self.values.values.len - (1 + tail_index)] = value;
return true;
}