Compare commits

...

5 Commits

Author SHA1 Message Date
kayomn ef537bef14 Merge pull request 'Refactor Kym' (#47) from kym-refactor into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: #47
2023-11-12 21:23:05 +01:00
kayomn 70746b4680 Unify calling interface for object accesses in Kym
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2023-11-12 20:12:04 +00:00
kayomn b0aa7166f9 Fill in missing documentation for Kym 2023-11-12 20:02:47 +00:00
kayomn dbba822c7a Add linear algebra utils for future graphics stuff 2023-11-12 18:55:16 +00:00
kayomn e5c18e4a14 Refactor Kym
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details
2023-11-12 13:09:30 +00:00
11 changed files with 2275 additions and 1114 deletions

View File

@ -57,7 +57,7 @@ pub const Stacking = struct {
}); });
} }
pub fn free(self: *Stacking) void { pub fn deinit(self: *Stacking) void {
while (self.head_region) |region| { while (self.head_region) |region| {
const next_region = region.next; const next_region = region.next;
@ -75,6 +75,15 @@ pub const Stacking = struct {
unreachable; unreachable;
} }
pub fn init(allocator: io.Allocator, min_region_size: usize) Stacking {
return Stacking{
.allocator = allocator,
.min_region_size = min_region_size,
.head_region = null,
.tail_region = null,
};
}
fn reallocate(self: *Stacking, _: usize, allocation: ?[]io.Byte, byte_size: usize) io.AllocationError![]io.Byte { fn reallocate(self: *Stacking, _: usize, allocation: ?[]io.Byte, byte_size: usize) io.AllocationError![]io.Byte {
if (allocation) |buffer| { if (allocation) |buffer| {
if (byte_size < buffer.len) { if (byte_size < buffer.len) {
@ -104,13 +113,4 @@ pub const Stacking = struct {
return @as([*]io.Byte, @ptrCast(tail_region.allocate(region_size)))[0 .. byte_size]; return @as([*]io.Byte, @ptrCast(tail_region.allocate(region_size)))[0 .. byte_size];
} }
pub fn make(allocator: io.Allocator, min_region_size: usize) Stacking {
return Stacking{
.allocator = allocator,
.min_region_size = min_region_size,
.head_region = null,
.tail_region = null,
};
}
}; };

View File

@ -16,6 +16,16 @@ pub fn Stack(comptime Value: type) type {
self.values = self.values[0 .. 0]; self.values = self.values[0 .. 0];
} }
pub fn deinit(self: *Self) void {
if (self.capacity == 0) {
return;
}
self.allocator.deallocate(self.values.ptr[0 .. self.capacity]);
self.values = &.{};
}
pub fn drop(self: *Self, count: usize) bool { pub fn drop(self: *Self, count: usize) bool {
if (math.checked_sub(self.values.len, count)) |updated_count| { if (math.checked_sub(self.values.len, count)) |updated_count| {
self.values = self.values[0 .. updated_count]; self.values = self.values[0 .. updated_count];
@ -26,16 +36,6 @@ pub fn Stack(comptime Value: type) type {
return false; return false;
} }
pub fn free(self: *Self) void {
if (self.capacity == 0) {
return;
}
self.allocator.deallocate(self.values.ptr[0 .. self.capacity]);
self.values = &.{};
}
pub fn grow(self: *Self, growth_amount: usize) io.AllocationError!void { pub fn grow(self: *Self, growth_amount: usize) io.AllocationError!void {
const grown_capacity = self.capacity + growth_amount; const grown_capacity = self.capacity + growth_amount;
const buffer = try self.allocator.reallocate(null, @sizeOf(Value) * grown_capacity); const buffer = try self.allocator.reallocate(null, @sizeOf(Value) * grown_capacity);
@ -51,11 +51,7 @@ pub fn Stack(comptime Value: type) type {
self.capacity = grown_capacity; self.capacity = grown_capacity;
} }
pub fn is_empty(self: Self) bool { pub fn init(allocator: io.Allocator) Self {
return self.values.len == 0;
}
pub fn make(allocator: io.Allocator) Self {
return .{ return .{
.allocator = allocator, .allocator = allocator,
.capacity = 0, .capacity = 0,
@ -63,7 +59,11 @@ pub fn Stack(comptime Value: type) type {
}; };
} }
pub fn pack(self: *Self) io.AllocationError!void { pub fn is_empty(self: Self) bool {
return self.values.len == 0;
}
pub fn pack(self: *Self) io.AllocationError![]Value {
const packed_size = self.values.len; const packed_size = self.values.len;
const buffer = try self.allocator.reallocate(null, @sizeOf(Value) * self.values.len); const buffer = try self.allocator.reallocate(null, @sizeOf(Value) * self.values.len);
@ -75,6 +75,8 @@ pub fn Stack(comptime Value: type) type {
self.values = @as([*]Value, @ptrCast(@alignCast(buffer)))[0 .. packed_size]; self.values = @as([*]Value, @ptrCast(@alignCast(buffer)))[0 .. packed_size];
self.capacity = packed_size; self.capacity = packed_size;
return self.values;
} }
pub fn peek(self: Self) ?Value { pub fn peek(self: Self) ?Value {

View File

@ -174,7 +174,7 @@ pub fn Table(comptime Key: type, comptime Value: type, comptime Traits: type) ty
self.count = 0; self.count = 0;
} }
pub fn free(self: *Self) void { pub fn deinit(self: *Self) void {
if (self.entries.len == 0) { if (self.entries.len == 0) {
return; return;
} }
@ -185,6 +185,15 @@ pub fn Table(comptime Key: type, comptime Value: type, comptime Traits: type) ty
self.count = 0; self.count = 0;
} }
pub fn init(allocator: io.Allocator, traits: Traits) Self {
return .{
.allocator = allocator,
.count = 0,
.entries = &.{},
.traits = traits,
};
}
pub fn insert(self: *Self, key: Key, value: Value) io.AllocationError!bool { pub fn insert(self: *Self, key: Key, value: Value) io.AllocationError!bool {
try self.rehash(load_max); try self.rehash(load_max);
@ -235,23 +244,14 @@ pub fn Table(comptime Key: type, comptime Value: type, comptime Traits: type) ty
return null; return null;
} }
pub fn make(allocator: io.Allocator, traits: Traits) Self {
return .{
.allocator = allocator,
.count = 0,
.entries = &.{},
.traits = traits,
};
}
pub fn rehash(self: *Self, max_load: f32) io.AllocationError!void { pub fn rehash(self: *Self, max_load: f32) io.AllocationError!void {
if (self.calculate_load_factor() <= max_load) { if (self.calculate_load_factor() <= max_load) {
return; return;
} }
var table = make(self.allocator, self.traits); var table = init(self.allocator, self.traits);
errdefer table.free(); errdefer table.deinit();
table.entries = allocate: { table.entries = allocate: {
const min_count = @max(1, self.count); const min_count = @max(1, self.count);
@ -266,7 +266,7 @@ pub fn Table(comptime Key: type, comptime Value: type, comptime Traits: type) ty
} }
} }
self.free(); self.deinit();
self.* = table; self.* = table;
} }

View File

@ -13,15 +13,15 @@ pub const Manifest = struct {
tick_rate: f32 = 60.0, tick_rate: f32 = 60.0,
pub fn load(self: *Manifest, env: *kym.RuntimeEnv) kym.RuntimeError!void { pub fn load(self: *Manifest, env: *kym.RuntimeEnv) kym.RuntimeError!void {
const manifest = try env.import(file.Path.from(&.{"app.ona"})) orelse return; const manifest = (try env.import(file.Path.from(&.{"app.ona"}))).pop() orelse return;
defer env.discard(manifest); defer env.release(manifest);
const width = @as(u16, get: { const width = @as(u16, get: {
if (try kym.get_field(env, manifest, "width")) |ref| { if (try kym.get_field(env, manifest, "width")) |ref| {
defer env.discard(ref); defer env.release(ref);
const fixed = try env.unwrap_fixed(ref); const fixed = try env.expect_fixed(ref);
if (fixed > 0 and fixed < coral.math.max_int(@typeInfo(@TypeOf(self.width)).Int)) { if (fixed > 0 and fixed < coral.math.max_int(@typeInfo(@TypeOf(self.width)).Int)) {
break: get @intCast(fixed); break: get @intCast(fixed);
@ -33,9 +33,9 @@ pub const Manifest = struct {
const height = @as(u16, get: { const height = @as(u16, get: {
if (try kym.get_field(env, manifest, "height")) |ref| { if (try kym.get_field(env, manifest, "height")) |ref| {
defer env.discard(ref); defer env.release(ref);
const fixed = try env.unwrap_fixed(ref); const fixed = try env.expect_fixed(ref);
if (fixed > 0 and fixed < coral.math.max_int(@typeInfo(@TypeOf(self.height)).Int)) { if (fixed > 0 and fixed < coral.math.max_int(@typeInfo(@TypeOf(self.height)).Int)) {
break: get @intCast(fixed); break: get @intCast(fixed);
@ -47,18 +47,18 @@ pub const Manifest = struct {
const tick_rate = @as(f32, get: { const tick_rate = @as(f32, get: {
if (try kym.get_field(env, manifest, "tick_rate")) |ref| { if (try kym.get_field(env, manifest, "tick_rate")) |ref| {
defer env.discard(ref); defer env.release(ref);
break: get @floatCast(try env.unwrap_float(ref)); break: get @floatCast(try env.expect_float(ref));
} }
break: get self.tick_rate; break: get self.tick_rate;
}); });
if (try kym.get_field(env, manifest, "title")) |ref| { if (try kym.get_field(env, manifest, "title")) |ref| {
defer env.discard(ref); defer env.release(ref);
const title_string = try env.unwrap_string(ref); const title_string = try env.expect_string(ref);
const limited_title_len = @min(title_string.len, self.title.len); const limited_title_len = @min(title_string.len, self.title.len);
coral.io.copy(&self.title, title_string[0 .. limited_title_len]); coral.io.copy(&self.title, title_string[0 .. limited_title_len]);

2
source/ona/gfx.zig Normal file
View File

@ -0,0 +1,2 @@
pub const lina = @import("./gfx/lina.zig");

181
source/ona/gfx/lina.zig Normal file
View File

@ -0,0 +1,181 @@
pub const Vector2 = struct {
x: f32,
y: f32,
pub const Scalars = [2]f32;
pub fn equals(self: Vector2, vector: Vector2) bool {
return self.x == vector.x and self.y == vector.y;
}
pub fn from_scalar(scalar: f32) Vector2 {
return .{
.x = scalar,
.y = scalar,
};
}
pub fn from_scalars(scalars: Scalars) Vector2 {
return .{
.x = scalars[0],
.y = scalars[1],
};
}
pub fn scalar_added(self: Vector2, scalar: f32) Vector2 {
return .{
.x = self.x + scalar,
.y = self.y + scalar,
};
}
pub fn scalar_divided(self: Vector2, scalar: f32) Vector2 {
return .{
.x = self.x / scalar,
.y = self.y / scalar,
};
}
pub fn scalar_multiplied(self: Vector2, scalar: f32) Vector2 {
return .{
.x = self.x * scalar,
.y = self.y * scalar,
};
}
pub fn to_scalars(self: Vector2) Scalars {
return .{self.x, self.y};
}
pub fn scalar_subtracted(self: Vector2, scalar: f32) Vector2 {
return .{
.x = self.x - scalar,
.y = self.y - scalar,
};
}
pub fn vector_added(self: Vector2, vector: Vector2) Vector2 {
return .{
.x = self.x + vector.x,
.y = self.y + vector.y,
};
}
pub fn vector_divided(self: Vector2, vector: Vector2) Vector2 {
return .{
.x = self.x / vector.x,
.y = self.y / vector.y,
};
}
pub fn vector_multiplied(self: Vector2, vector: Vector2) Vector2 {
return .{
.x = self.x * vector.x,
.y = self.y * vector.y,
};
}
pub fn vector_subtracted(self: Vector2, vector: Vector2) Vector2 {
return .{
.x = self.x - vector.x,
.y = self.y - vector.y,
};
}
};
pub const Vector3 = struct {
x: f32,
y: f32,
z: f32,
pub const Scalars = [3]f32;
pub fn equals(self: Vector3, vector: Vector3) bool {
return self.x == vector.x and self.y == vector.y and self.z == vector.z;
}
pub fn from_scalar(scalar: f32) Vector3 {
return .{
.x = scalar,
.y = scalar,
.z = scalar,
};
}
pub fn from_scalars(scalars: Scalars) Vector3 {
return .{
.x = scalars[0],
.y = scalars[1],
.z = scalars[2],
};
}
pub fn scalar_added(self: Vector3, scalar: f32) Vector3 {
return .{
.x = self.x + scalar,
.y = self.y + scalar,
.z = self.z + scalar,
};
}
pub fn scalar_divided(self: Vector3, scalar: f32) Vector3 {
return .{
.x = self.x / scalar,
.y = self.y / scalar,
.z = self.z / scalar,
};
}
pub fn scalar_multiplied(self: Vector3, scalar: f32) Vector3 {
return .{
.x = self.x * scalar,
.y = self.y * scalar,
.z = self.z * scalar,
};
}
pub fn scalar_subtracted(self: Vector3, scalar: f32) Vector3 {
return .{
.x = self.x - scalar,
.y = self.y - scalar,
.z = self.z - scalar,
};
}
pub fn to_scalars(self: Vector3) Scalars {
return .{self.x, self.y, self.z};
}
pub fn vector_added(self: Vector3, other: Vector3) Vector3 {
return .{
.x = self.x + other.x,
.y = self.y + other.y,
.z = self.z + other.z,
};
}
pub fn vector_divided(self: Vector3, other: Vector3) Vector3 {
return .{
.x = self.x / other.x,
.y = self.y / other.y,
.z = self.z / other.z,
};
}
pub fn vector_multiplied(self: Vector3, other: Vector3) Vector3 {
return .{
.x = self.x * other.x,
.y = self.y * other.y,
.z = self.z * other.z,
};
}
pub fn vector_subtracted(self: Vector3, other: Vector3) Vector3 {
return .{
.x = self.x - other.x,
.y = self.y - other.y,
.z = self.z - other.z,
};
}
};

File diff suppressed because it is too large Load Diff

View File

@ -10,13 +10,13 @@ const tokens = @import("./tokens.zig");
const tree = @import("./tree.zig"); const tree = @import("./tree.zig");
name: *kym.RuntimeRef, name: *kym.RuntimeObj,
arity: u8, arity: u8,
opcodes: OpcodeList, opcodes: OpcodeList,
lines: LineList, lines: LineList,
cursor: usize, cursor: usize,
constants: ConstList, constants: ConstList,
bindings: []?*kym.RuntimeRef, bindings: []?*kym.RuntimeObj,
const Builtin = enum { const Builtin = enum {
import, import,
@ -118,9 +118,9 @@ const Compiler = struct {
}, },
.lambda_construct => |lambda_construct| { .lambda_construct => |lambda_construct| {
var chunk = try Self.make(self.env, name orelse "<lambda>", lambda_construct.environment); var chunk = try Self.init(self.env, name orelse "<lambda>", lambda_construct.environment);
errdefer chunk.free(self.env); errdefer chunk.deinit(self.env);
if (lambda_construct.environment.capture_count == 0) { if (lambda_construct.environment.capture_count == 0) {
try self.chunk.write(expression.line, .{.push_const = try self.declare_chunk(chunk)}); try self.chunk.write(expression.line, .{.push_const = try self.declare_chunk(chunk)});
@ -193,7 +193,7 @@ const Compiler = struct {
return; return;
} }
if (try self.get_binding_index(environment, declaration_get.declaration)) |index| { if (try get_binding_index(environment, declaration_get.declaration)) |index| {
try self.chunk.write(expression.line, .{.push_binding = index}); try self.chunk.write(expression.line, .{.push_binding = index});
if (is_declaration_boxed(declaration_get.declaration)) { if (is_declaration_boxed(declaration_get.declaration)) {
@ -208,19 +208,19 @@ const Compiler = struct {
.declaration_set => |declaration_set| { .declaration_set => |declaration_set| {
if (get_local_index(environment, declaration_set.declaration)) |index| { if (get_local_index(environment, declaration_set.declaration)) |index| {
try self.compile_expression(environment, declaration_set.assign, null);
if (is_declaration_boxed(declaration_set.declaration)) { if (is_declaration_boxed(declaration_set.declaration)) {
try self.chunk.write(expression.line, .{.push_local = index}); try self.chunk.write(expression.line, .{.push_local = index});
try self.compile_expression(environment, declaration_set.assign, null);
try self.chunk.write(expression.line, .set_box); try self.chunk.write(expression.line, .set_box);
} else { } else {
try self.compile_expression(environment, declaration_set.assign, null);
try self.chunk.write(expression.line, .{.set_local = index}); try self.chunk.write(expression.line, .{.set_local = index});
} }
return; return;
} }
if (try self.get_binding_index(environment, declaration_set.declaration)) |index| { if (try get_binding_index(environment, declaration_set.declaration)) |index| {
try self.compile_expression(environment, declaration_set.assign, null); try self.compile_expression(environment, declaration_set.assign, null);
try self.chunk.write(expression.line, .{.push_binding = index}); try self.chunk.write(expression.line, .{.push_binding = index});
@ -345,9 +345,9 @@ const Compiler = struct {
}); });
} }
const constant = try self.env.new_dynamic(coral.io.bytes_of(&chunk), typeinfo); const constant = (try self.env.new_dynamic(coral.io.bytes_of(&chunk), typeinfo)).pop().?;
errdefer self.env.discard(constant); errdefer self.env.release(constant);
try self.chunk.constants.push_one(constant); try self.chunk.constants.push_one(constant);
@ -361,9 +361,9 @@ const Compiler = struct {
}); });
} }
const constant = try self.env.new_fixed(fixed); const constant = (try self.env.new_fixed(fixed)).pop().?;
errdefer self.env.discard(constant); errdefer self.env.release(constant);
try self.chunk.constants.push_one(constant); try self.chunk.constants.push_one(constant);
@ -377,9 +377,9 @@ const Compiler = struct {
}); });
} }
const constant = try self.env.new_float(float); const constant = (try self.env.new_float(float)).pop().?;
errdefer self.env.discard(constant); errdefer self.env.release(constant);
try self.chunk.constants.push_one(constant); try self.chunk.constants.push_one(constant);
@ -393,9 +393,9 @@ const Compiler = struct {
}); });
} }
const constant = try self.env.new_string(string); const constant = (try self.env.new_string(string)).pop().?;
errdefer self.env.discard(constant); errdefer self.env.release(constant);
try self.chunk.constants.push_one(constant); try self.chunk.constants.push_one(constant);
@ -409,16 +409,16 @@ const Compiler = struct {
}); });
} }
const constant = try self.env.new_symbol(symbol); const constant = (try self.env.new_symbol(symbol)).pop().?;
errdefer self.env.discard(constant); errdefer self.env.release(constant);
try self.chunk.constants.push_one(constant); try self.chunk.constants.push_one(constant);
return @intCast(self.chunk.constants.values.len - 1); return @intCast(self.chunk.constants.values.len - 1);
} }
fn get_binding_index(self: *const Compiler, environment: *const tree.Environment, declaration: *const tree.Declaration) kym.RuntimeError!?u8 { fn get_binding_index(environment: *const tree.Environment, declaration: *const tree.Declaration) kym.RuntimeError!?u8 {
var binding_index = @as(u8, 0); var binding_index = @as(u8, 0);
while (binding_index < environment.capture_count) : (binding_index += 1) { while (binding_index < environment.capture_count) : (binding_index += 1) {
@ -430,7 +430,7 @@ const Compiler = struct {
target_environment = target_environment.enclosing orelse return null; target_environment = target_environment.enclosing orelse return null;
} }
try kym.assert(self.env, capture.* == .declaration_index); coral.debug.assert(capture.* == .declaration_index);
if (&target_environment.declarations[capture.declaration_index] == declaration) { if (&target_environment.declarations[capture.declaration_index] == declaration) {
return binding_index; return binding_index;
@ -459,7 +459,7 @@ const Compiler = struct {
} }
}; };
const ConstList = coral.list.Stack(*kym.RuntimeRef); const ConstList = coral.list.Stack(*kym.RuntimeObj);
const LineList = coral.list.Stack(tokens.Line); const LineList = coral.list.Stack(tokens.Line);
@ -507,11 +507,33 @@ const OpcodeList = coral.list.Stack(Opcode);
const Self = @This(); const Self = @This();
pub fn dump(chunk: Self, env: *kym.RuntimeEnv) kym.RuntimeError!*kym.RuntimeRef { pub fn deinit(self: *Self, env: *kym.RuntimeEnv) void {
var opcode_cursor = @as(u32, 0); while (self.constants.pop()) |constant| {
var buffer = coral.list.ByteStack.make(env.allocator); env.release(constant);
}
defer buffer.free(); self.constants.deinit();
self.opcodes.deinit();
env.release(self.name);
if (self.bindings.len != 0) {
for (self.bindings) |binding| {
if (binding) |value| {
env.release(value);
}
}
env.allocator.deallocate(self.bindings);
}
self.bindings = &.{};
}
pub fn dump(chunk: Self, env: *kym.RuntimeEnv) kym.RuntimeError!*kym.RuntimeObj {
var opcode_cursor = @as(u32, 0);
var buffer = coral.list.ByteStack.init(env.allocator);
defer buffer.deinit();
const writer = coral.list.stack_as_writer(&buffer); const writer = coral.list.stack_as_writer(&buffer);
@ -528,15 +550,11 @@ pub fn dump(chunk: Self, env: *kym.RuntimeEnv) kym.RuntimeError!*kym.RuntimeRef
.push_false => coral.utf8.print_string(writer, "push false\n"), .push_false => coral.utf8.print_string(writer, "push false\n"),
.push_const => |push_const| print: { .push_const => |push_const| print: {
try kym.assert(env, push_const < chunk.constants.values.len); const string_ref = (try (try env.push(try chunk.get_constant(env, push_const))).to_string()).pop().?;
const string_ref = try env.to_string(chunk.constants.values[push_const]); defer env.release(string_ref);
defer env.discard(string_ref); const string = string_ref.is_string();
const string = string_ref.as_string();
coral.debug.assert(string != null);
break: print coral.utf8.print_formatted(writer, "push const ({value})\n", .{.value = string.?}); break: print coral.utf8.print_formatted(writer, "push const ({value})\n", .{.value = string.?});
}, },
@ -599,407 +617,247 @@ pub fn dump(chunk: Self, env: *kym.RuntimeEnv) kym.RuntimeError!*kym.RuntimeRef
}; };
} }
return env.new_string(buffer.values); return (try env.new_string(buffer.values)).pop().?;
} }
pub fn execute(self: *Self, env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef { pub fn execute(self: *Self, env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeObj {
self.cursor = 0; self.cursor = 0;
while (self.cursor < self.opcodes.values.len) : (self.cursor += 1) { while (self.cursor < self.opcodes.values.len) : (self.cursor += 1) {
switch (self.opcodes.values[self.cursor]) { switch (self.opcodes.values[self.cursor]) {
.ret => break, .ret => break,
.pop => env.discard(),
.pop => { .push_nil => _ = try env.push(null),
if (try env.pop_local()) |ref| { .push_true => _ = try env.new_boolean(true),
env.discard(ref); .push_false => _ = try env.new_boolean(false),
} .push_const => |push_const| _ = try env.push(try self.get_constant(env, push_const)),
}, .push_local => |push_local| _ = try env.local_get(push_local),
.push_top => _ = try env.local_top(),
.push_nil => try env.locals.push_one(null),
.push_true => try env.locals.push_one(try env.new_boolean(true)),
.push_false => try env.locals.push_one(try env.new_boolean(false)),
.push_const => |push_const| {
try kym.assert(env, push_const < self.constants.values.len);
try env.locals.push_one(self.constants.values[push_const].acquire());
},
.push_local => |push_local| {
try kym.assert(env, push_local < (env.locals.values.len - frame.locals_top));
if (env.locals.values[frame.locals_top + push_local]) |local| {
try env.locals.push_one(local.acquire());
} else {
try env.locals.push_one(null);
}
},
.push_top => {
const frame_locals = env.locals.values[frame.locals_top ..];
try kym.assert(env, frame_locals.len != 0);
if (frame_locals[frame_locals.len - 1]) |local| {
try env.locals.push_one(local.acquire());
} else {
try env.locals.push_one(null);
}
},
.push_table => |push_table| { .push_table => |push_table| {
const table = try env.new_table(); const table = (try env.new_table()).pop().?;
errdefer env.discard(table); errdefer env.release(table);
{ if (push_table != 0) {
var popped = @as(usize, 0); var popped = @as(usize, 0);
while (popped < push_table) : (popped += 1) { while (popped < push_table) : (popped += 1) {
const index = try env.expect(try env.pop_local()); const index = try env.expect_object(env.pop());
defer env.discard(index); defer env.release(index);
if (try env.pop_local()) |value| { if (env.pop()) |object| {
defer env.discard(value); defer env.release(object);
try env.set(table, index, value); try (try env.push(table)).index_set(index, object);
} }
} }
} }
try env.locals.push_one(table); _ = try env.push(table);
}, },
.push_boxed => { .push_boxed => {
const value = try env.pop_local(); const value = env.pop();
defer { defer {
if (value) |ref| { if (value) |object| {
env.discard(ref); env.release(object);
} }
} }
const boxable = try env.new_boxed(value); _ = try env.new_boxed(value);
errdefer env.discard(boxable);
try env.locals.push_one(boxable);
}, },
.push_binding => |push_binding| { .push_binding => |push_binding| _ = try env.push(try self.get_binding(env, push_binding)),
try kym.assert(env, push_binding <= self.bindings.len); .push_concat => |push_concat| _ = try env.concat(push_concat),
try env.locals.push_one(if (self.bindings[push_binding]) |value| value.acquire() else null);
},
.push_concat => |push_concat| {
const frame_locals = env.locals.values[frame.locals_top ..];
try kym.assert(env, push_concat <= frame_locals.len);
const concat_locals = frame_locals[(frame_locals.len - push_concat) .. frame_locals.len];
for (concat_locals) |value| {
_ = try env.expect(value);
}
const concatenated_value = try env.concat(@ptrCast(concat_locals));
errdefer env.discard(concatenated_value);
var to_pop = concat_locals.len;
while (to_pop != 0) : (to_pop -= 1) {
const popped = env.pop_local() catch unreachable;
coral.debug.assert(popped != null);
env.discard(popped.?);
}
try env.locals.push_one(concatenated_value);
},
.bind => |bind| { .bind => |bind| {
const callable = try env.expect(try env.pop_local()); const callable = try env.expect_object(env.pop());
errdefer env.discard(callable); defer env.release(callable);
const chunk = @as(*Self, @ptrCast(@alignCast(try env.unwrap_dynamic(callable, typeinfo)))); const chunk = @as(*Self, @ptrCast(@alignCast(try env.expect_dynamic(callable, typeinfo))));
chunk.bindings = try coral.io.allocate_many(env.allocator, bind, @as(?*kym.RuntimeRef, null)); if (chunk.bindings.len != 0) {
return env.raise(error.IllegalState, "cannot bind values to an already-bound chunk", .{});
}
chunk.bindings = try coral.io.allocate_many(env.allocator, bind, @as(?*kym.RuntimeObj, null));
for (0 .. bind) |index| { for (0 .. bind) |index| {
const value = try env.pop_local(); const value = env.pop();
errdefer { errdefer {
if (value) |ref| { if (value) |object| {
env.discard(ref); env.release(object);
} }
} }
const binding = &chunk.bindings[index]; chunk.bindings[index] = value;
if (binding.*) |*existing_binding| {
env.discard(existing_binding.*);
} }
binding.* = value; _ = try env.push(callable);
}
try env.locals.push_one(callable);
}, },
.push_builtin => |push_builtin| { .push_builtin => |push_builtin| _ = try env.new_syscall(switch (push_builtin) {
const builtin_syscall = try env.new_syscall(switch (push_builtin) {
.import => syscall_import, .import => syscall_import,
.print => syscall_print, .print => syscall_print,
.vec2 => syscall_vec2, .vec2 => syscall_vec2,
.vec3 => syscall_vec3, .vec3 => syscall_vec3,
}); }),
errdefer env.discard(builtin_syscall); .set_local => |local_set| _ = try env.local_set(local_set, env.pop()),
.get_box => _ = try env.boxed_get(),
try env.locals.push_one(builtin_syscall);
},
.set_local => |local_set| {
const local = &env.locals.values[frame.locals_top + local_set];
if (local.*) |previous_local| {
env.discard(previous_local);
}
local.* = try env.pop_local();
},
.get_box => {
const box = try env.expect(try env.pop_local());
defer env.discard(box);
if (try env.get_boxed(box)) |unboxed| {
errdefer env.discard(unboxed);
try env.locals.push_one(unboxed);
} else {
try env.locals.push_one(null);
}
},
.set_box => { .set_box => {
const box = try env.expect(try env.pop_local()); const value = env.pop();
defer env.discard(box); defer {
if (value) |object| {
env.release(object);
}
}
const value = try env.expect(try env.pop_local()); try env.boxed_set(value);
errdefer env.discard(value);
try env.set_boxed(box, value);
}, },
.get_dynamic => { .get_dynamic => {
const index = try env.expect(try env.pop_local()); const index = try env.expect_object(env.pop());
defer env.discard(index); defer env.release(index);
const indexable = try env.expect(try env.pop_local()); _ = try env.index_get(index);
defer env.discard(indexable);
const value = try env.get(indexable, index);
errdefer {
if (value) |ref| {
env.discard(ref);
}
}
try env.locals.push_one(value);
}, },
.set_dynamic => { .set_dynamic => {
const value = try env.pop_local(); const value = env.pop();
defer { defer {
if (value) |ref| { if (value) |object| {
env.discard(ref); env.release(object);
} }
} }
const index = try env.expect(try env.pop_local()); const index = try env.expect_object(env.pop());
defer env.discard(index); defer env.release(index);
const indexable = try env.expect(try env.pop_local()); try env.index_set(index, value);
defer env.discard(indexable);
try env.set(indexable, index, value);
}, },
.call => |call| { .call => |call| _ = try env.call(call),
const result = call: {
const callable = try env.expect(try env.pop_local());
defer env.discard(callable);
const call_frame = try env.push_frame(callable, call);
defer env.pop_frame();
break: call try env.call_frame(&call_frame);
};
errdefer {
if (result) |ref| {
env.discard(ref);
}
}
try env.locals.push_one(result);
},
.not => { .not => {
if (try env.pop_local()) |value| { const object = try env.expect_object(env.pop());
defer env.discard(value);
try env.locals.push_one(try env.new_boolean(!value.is_truthy())); defer env.release(object);
} else {
try env.locals.push_one(try env.new_boolean(true)); _ = try env.new_boolean(object.is_false());
}
}, },
.neg => { .neg => _ = try env.neg(),
const value = try env.expect(try env.pop_local());
defer env.discard(value);
try env.locals.push_one(try env.neg(value));
},
.add => { .add => {
const rhs = try env.expect(try env.pop_local()); const addable = try env.expect_object(env.pop());
defer env.discard(rhs); defer env.release(addable);
const lhs = try env.expect(try env.pop_local()); _ = switch (try env.expect_numeric(addable)) {
.fixed => |fixed| try env.fixed_add(fixed),
defer env.discard(lhs); .float => |float| try env.float_add(float),
.vector2 => |vector2| try env.vector2_add(vector2),
try env.locals.push_one(try env.add(lhs, rhs)); .vector3 => |vector3| try env.vector3_add(vector3),
};
}, },
.sub => { .sub => {
const rhs = try env.expect(try env.pop_local()); const subtractable = try env.expect_object(env.pop());
defer env.discard(rhs); defer env.release(subtractable);
const lhs = try env.expect(try env.pop_local()); _ = switch (try env.expect_numeric(subtractable)) {
.fixed => |fixed| try env.fixed_subtract(fixed),
defer env.discard(lhs); .float => |float| try env.float_subtract(float),
.vector2 => |vector2| try env.vector2_subtract(vector2),
try env.locals.push_one(try env.sub(lhs, rhs)); .vector3 => |vector3| try env.vector3_subtract(vector3),
};
}, },
.mul => { .mul => {
const rhs = try env.expect(try env.pop_local()); const multiplicable = try env.expect_object(env.pop());
defer env.discard(rhs); defer env.release(multiplicable);
const lhs = try env.expect(try env.pop_local()); _ = switch (try env.expect_numeric(multiplicable)) {
.fixed => |fixed| try env.fixed_multiply(fixed),
defer env.discard(lhs); .float => |float| try env.float_multiply(float),
.vector2 => |vector2| try env.vector2_multiply(vector2),
try env.locals.push_one(try env.mul(lhs, rhs)); .vector3 => |vector3| try env.vector3_multiply(vector3),
};
}, },
.div => { .div => {
const rhs = try env.expect(try env.pop_local()); const divisible = try env.expect_object(env.pop());
defer env.discard(rhs); defer env.release(divisible);
const lhs = try env.expect(try env.pop_local()); _ = switch (try env.expect_numeric(divisible)) {
.fixed => |fixed| try env.fixed_divide(fixed),
defer env.discard(lhs); .float => |float| try env.float_divide(float),
.vector2 => |vector2| try env.vector2_divide(vector2),
try env.locals.push_one(try env.div(lhs, rhs)); .vector3 => |vector3| try env.vector3_divide(vector3),
};
}, },
.eql => { .eql => {
if (try env.pop_local()) |rhs| { if (env.pop()) |equatable| {
env.discard(rhs); defer env.release(equatable);
if (try env.pop_local()) |lhs| { _ = try env.equals_object(equatable);
env.discard(lhs);
try env.locals.push_one(try env.new_boolean(lhs.equals(rhs)));
} else { } else {
try env.locals.push_one(try env.new_boolean(false)); _ = try env.equals_nil();
}
} else {
if (try env.pop_local()) |lhs| {
env.discard(lhs);
try env.locals.push_one(try env.new_boolean(false));
} else {
try env.locals.push_one(try env.new_boolean(true));
}
} }
}, },
.cgt => { .cgt => {
const rhs = try env.expect(try env.pop_local()); const comparable = try env.expect_object(env.pop());
defer env.discard(rhs); defer env.release(comparable);
const lhs = try env.expect(try env.pop_local()); _ = try env.compare_greater(comparable);
defer env.discard(lhs);
try env.locals.push_one(try env.new_boolean(try env.compare(lhs, rhs) > 0));
}, },
.clt => { .clt => {
const rhs = try env.expect(try env.pop_local()); const comparable = try env.expect_object(env.pop());
defer env.discard(rhs); defer env.release(comparable);
const lhs = try env.expect(try env.pop_local()); _ = try env.compare_less(comparable);
defer env.discard(lhs);
try env.locals.push_one(try env.new_boolean(try env.compare(lhs, rhs) < 0));
}, },
.cge => { .cge => {
const rhs = try env.expect(try env.pop_local()); const comparable = try env.expect_object(env.pop());
defer env.discard(rhs); defer env.release(comparable);
const lhs = try env.expect(try env.pop_local()); _ = try env.compare_greater_equals(comparable);
defer env.discard(lhs);
try env.locals.push_one(try env.new_boolean(try env.compare(lhs, rhs) >= 0));
}, },
.cle => { .cle => {
const rhs = try env.expect(try env.pop_local()); const comparable = try env.expect_object(env.pop());
defer env.discard(rhs); defer env.release(comparable);
const lhs = try env.expect(try env.pop_local()); _ = try env.compare_less_equals(comparable);
defer env.discard(lhs);
try env.locals.push_one(try env.new_boolean(try env.compare(lhs, rhs) <= 0));
}, },
.jf => |jf| { .jf => |jf| {
if (try env.pop_local()) |condition| { if (env.pop()) |condition| {
defer env.discard(condition); defer env.release(condition);
if (!condition.is_truthy()) { if (condition.is_false()) {
self.cursor = jf; self.cursor = jf;
} }
} else { } else {
@ -1008,10 +866,10 @@ pub fn execute(self: *Self, env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.R
}, },
.jt => |jt| { .jt => |jt| {
if (try env.pop_local()) |condition| { if (env.pop()) |condition| {
defer env.discard(condition); defer env.release(condition);
if (condition.is_truthy()) { if (condition.is_true()) {
self.cursor = jt; self.cursor = jt;
} }
} }
@ -1019,37 +877,31 @@ pub fn execute(self: *Self, env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.R
} }
} }
return env.pop_local(); return env.pop();
} }
pub fn free(self: *Self, env: *kym.RuntimeEnv) void { fn get_binding(self: *Self, env: *kym.RuntimeEnv, index: usize) kym.RuntimeError!?*kym.RuntimeObj {
while (self.constants.pop()) |constant| { if (index >= self.bindings.len) {
env.discard(constant); return env.raise(error.IllegalState, "invalid binding", .{});
} }
self.constants.free(); return self.bindings[index];
self.opcodes.free();
env.discard(self.name);
if (self.bindings.len != 0) {
for (self.bindings) |binding| {
if (binding) |value| {
env.discard(value);
}
}
env.allocator.deallocate(self.bindings);
}
self.bindings = &.{};
} }
pub fn make(env: *kym.RuntimeEnv, name: []const coral.io.Byte, environment: *const tree.Environment) kym.RuntimeError!Self { fn get_constant(self: *const Self, env: *kym.RuntimeEnv, index: usize) kym.RuntimeError!*kym.RuntimeObj {
if (index >= self.constants.values.len) {
return env.raise(error.IllegalState, "invalid constant", .{});
}
return self.constants.values[index];
}
pub fn init(env: *kym.RuntimeEnv, name: []const coral.io.Byte, environment: *const tree.Environment) kym.RuntimeError!Self {
var chunk = Self{ var chunk = Self{
.name = try env.new_symbol(name), .name = (try env.new_symbol(name)).pop().?,
.opcodes = OpcodeList.make(env.allocator), .opcodes = OpcodeList.init(env.allocator),
.constants = ConstList.make(env.allocator), .constants = ConstList.init(env.allocator),
.lines = LineList.make(env.allocator), .lines = LineList.init(env.allocator),
.bindings = &.{}, .bindings = &.{},
.arity = environment.argument_count, .arity = environment.argument_count,
.cursor = 0, .cursor = 0,
@ -1065,38 +917,81 @@ pub fn make(env: *kym.RuntimeEnv, name: []const coral.io.Byte, environment: *con
return chunk; return chunk;
} }
fn syscall_import(env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef { fn syscall_import(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeObj {
return env.import(file.Path.from(&.{try env.unwrap_string(try frame.expect_arg(env, 0))})); const arg = (try env.arg_get(0)).pop() orelse {
return env.raise(error.BadOperation, "`@import` requires one argument to be a valid import path", .{});
};
defer env.release(arg);
return (try env.import(file.Path.from(&.{try env.expect_string(arg)}))).pop();
} }
fn syscall_print(env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef { fn syscall_print(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeObj {
env.print(try env.unwrap_string(try frame.expect_arg(env, 0))); const string = (try (try env.arg_get(0)).to_string()).pop().?;
defer env.release(string);
env.print(string.is_string().?);
return null; return null;
} }
fn syscall_vec2(env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef { fn syscall_vec2(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeObj {
const x = @as(f32, @floatCast(try env.unwrap_float(try frame.expect_arg(env, 0)))); const x = @as(f32, get_x: {
const x = (try env.arg_get(0)).pop() orelse {
return env.raise(error.BadOperation, "a first argument is required to create a vector", .{});
};
if (frame.has_arg(env, 1)) |y| { defer env.release(x);
return env.new_vector2(x, @floatCast(try env.unwrap_float(y)));
break: get_x @floatCast(try env.expect_float(x));
});
if ((try env.arg_get(1)).pop()) |y| {
defer env.release(y);
return (try env.new_vector2(.{
.y = @floatCast(try env.expect_float(y)),
.x = x,
})).pop();
} }
return env.new_vector2(x, x); return (try env.new_vector2(kym.Vector2.from_scalar(x))).pop();
} }
fn syscall_vec3(env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef { fn syscall_vec3(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeObj {
const x = @as(f32, @floatCast(try env.unwrap_float(try frame.expect_arg(env, 0)))); const x = @as(f32, get_x: {
const x = (try env.arg_get(0)).pop() orelse {
return env.raise(error.BadOperation, "a first argument is required to create a vector", .{});
};
if (frame.has_arg(env, 1)) |y| { defer env.release(x);
return env.new_vector3(
x, break: get_x @floatCast(try env.expect_float(x));
@floatCast(try env.unwrap_float(y)), });
@floatCast(try env.unwrap_float(try frame.expect_arg(env, 2))),
); if ((try env.arg_get(1)).pop()) |y| {
defer env.release(y);
return (try env.new_vector3(.{
.z = @as(f32, get_z: {
const z = (try env.arg_get(0)).pop() orelse {
return env.raise(error.BadOperation,
"a third argument is required to create a vector if a first and second exist", .{});
};
defer env.release(z);
break: get_z @floatCast(try env.expect_float(z));
}),
.y = @floatCast(try env.expect_float(y)),
.x = x,
})).pop();
} }
return env.new_vector3(x, x, x); return (try env.new_vector3(kym.Vector3.from_scalar(x))).pop();
} }
pub const typeinfo = &kym.Typeinfo{ pub const typeinfo = &kym.Typeinfo{
@ -1107,16 +1002,16 @@ pub const typeinfo = &kym.Typeinfo{
.to_string = typeinfo_to_string, .to_string = typeinfo_to_string,
}; };
fn typeinfo_call(env: *kym.RuntimeEnv, userdata: []coral.io.Byte, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef { fn typeinfo_call(context: kym.Typeinfo.CallContext) kym.RuntimeError!?*kym.RuntimeObj {
return @as(*Self, @ptrCast(@alignCast(userdata))).execute(env, frame); return @as(*Self, @ptrCast(@alignCast(context.userdata))).execute(context.env);
} }
fn typeinfo_destruct(env: *kym.RuntimeEnv, userdata: []coral.io.Byte) void { fn typeinfo_destruct(context: kym.Typeinfo.DestructContext) void {
@as(*Self, @ptrCast(@alignCast(userdata))).free(env); @as(*Self, @ptrCast(@alignCast(context.userdata))).deinit(context.env);
} }
fn typeinfo_to_string(env: *kym.RuntimeEnv, userdata: []coral.io.Byte) coral.io.AllocationError!*kym.RuntimeRef { fn typeinfo_to_string(context: kym.Typeinfo.ToStringContext) kym.RuntimeError!*kym.RuntimeObj {
return env.to_string(@as(*Self, @ptrCast(@alignCast(userdata))).name); return (try (try context.env.push(@as(*Self, @ptrCast(@alignCast(context.userdata))).name)).to_string()).pop().?;
} }
pub fn write(self: *Self, line: tokens.Line, opcode: Opcode) coral.io.AllocationError!void { pub fn write(self: *Self, line: tokens.Line, opcode: Opcode) coral.io.AllocationError!void {

View File

@ -5,41 +5,41 @@ const kym = @import("../kym.zig");
associative: RefTable, associative: RefTable,
contiguous: RefList, contiguous: RefList,
const RefList = coral.list.Stack(?*kym.RuntimeRef); const RefList = coral.list.Stack(?*kym.RuntimeObj);
const RefTable = coral.map.Table(*kym.RuntimeRef, *kym.RuntimeRef, struct { const RefTable = coral.map.Table(*kym.RuntimeObj, *kym.RuntimeObj, struct {
pub const hash = kym.RuntimeRef.hash; pub const hash = kym.RuntimeObj.hash;
pub const equals = kym.RuntimeRef.equals; pub const equals = kym.RuntimeObj.equals;
}); });
const Self = @This(); const Self = @This();
pub fn free(self: *Self, env: *kym.RuntimeEnv) void { pub fn deinit(self: *Self, env: *kym.RuntimeEnv) void {
{ {
var field_iterable = self.associative.as_iterable(); var field_iterable = self.associative.as_iterable();
while (field_iterable.next()) |entry| { while (field_iterable.next()) |entry| {
env.discard(entry.key); env.release(entry.key);
env.discard(entry.value); env.release(entry.value);
} }
} }
self.associative.free(); self.associative.deinit();
while (self.contiguous.pop()) |value| { while (self.contiguous.pop()) |value| {
if (value) |ref| { if (value) |ref| {
env.discard(ref); env.release(ref);
} }
} }
self.contiguous.free(); self.contiguous.deinit();
} }
pub fn make(env: *kym.RuntimeEnv) Self { pub fn init(env: *kym.RuntimeEnv) Self {
return .{ return .{
.associative = RefTable.make(env.allocator, .{}), .associative = RefTable.init(env.allocator, .{}),
.contiguous = RefList.make(env.allocator), .contiguous = RefList.init(env.allocator),
}; };
} }
@ -51,41 +51,41 @@ pub const typeinfo = &kym.Typeinfo{
.set = typeinfo_set, .set = typeinfo_set,
}; };
fn typeinfo_destruct(env: *kym.RuntimeEnv, userdata: []coral.io.Byte) void { fn typeinfo_destruct(context: kym.Typeinfo.DestructContext) void {
@as(*Self, @ptrCast(@alignCast(userdata))).free(env); @as(*Self, @ptrCast(@alignCast(context.userdata))).deinit(context.env);
} }
fn typeinfo_get(env: *kym.RuntimeEnv, userdata: []coral.io.Byte, index: *const kym.RuntimeRef) kym.RuntimeError!?*kym.RuntimeRef { fn typeinfo_get(context: kym.Typeinfo.GetContext) kym.RuntimeError!?*kym.RuntimeObj {
const table = @as(*Self, @ptrCast(@alignCast(userdata))); const table = @as(*Self, @ptrCast(@alignCast(context.userdata)));
const acquired_index = index.acquire(); const index = (try context.push_index()).pop().?;
defer env.discard(acquired_index); defer context.env.release(index);
if (acquired_index.as_fixed()) |fixed| { if (index.is_fixed()) |fixed| {
if (fixed < 0) { if (fixed < 0) {
// TODO: Negative indexing. // TODO: Negative indexing.
unreachable; unreachable;
} }
if (fixed < table.contiguous.values.len) { if (fixed < table.contiguous.values.len) {
return (table.contiguous.values[@intCast(fixed)] orelse return null).acquire(); return table.contiguous.values[@intCast(fixed)];
} }
} }
if (table.associative.lookup(acquired_index)) |value| { if (table.associative.lookup(index)) |value| {
return value.acquire(); return value;
} }
return null; return null;
} }
fn typeinfo_set(env: *kym.RuntimeEnv, userdata: []coral.io.Byte, index: *const kym.RuntimeRef, value: ?*const kym.RuntimeRef) kym.RuntimeError!void { fn typeinfo_set(context: kym.Typeinfo.SetContext) kym.RuntimeError!void {
const table = @as(*Self, @ptrCast(@alignCast(userdata))); const table = @as(*Self, @ptrCast(@alignCast(context.userdata)));
const acquired_index = index.acquire(); const index = (try context.push_index()).pop().?;
errdefer env.discard(acquired_index); errdefer context.env.release(index);
if (acquired_index.as_fixed()) |fixed| { if (index.is_fixed()) |fixed| {
if (fixed < 0) { if (fixed < 0) {
// TODO: Negative indexing. // TODO: Negative indexing.
unreachable; unreachable;
@ -95,28 +95,34 @@ fn typeinfo_set(env: *kym.RuntimeEnv, userdata: []coral.io.Byte, index: *const k
const maybe_replacing = &table.contiguous.values[@intCast(fixed)]; const maybe_replacing = &table.contiguous.values[@intCast(fixed)];
if (maybe_replacing.*) |replacing| { if (maybe_replacing.*) |replacing| {
env.discard(replacing); context.env.release(replacing);
} }
maybe_replacing.* = if (value) |ref| ref.acquire() else null; if ((try context.push_value()).pop()) |value| {
errdefer context.env.release(value);
return; maybe_replacing.* = value;
} } else {
} maybe_replacing.* = null;
const acquired_value = (value orelse {
if (table.associative.remove(acquired_index)) |removed| {
env.discard(removed.key);
env.discard(removed.value);
} }
return; return;
}).acquire(); }
}
errdefer env.discard(acquired_value); const value = (try context.push_value()).pop() orelse {
if (table.associative.remove(index)) |removed| {
context.env.release(removed.key);
context.env.release(removed.value);
}
if (try table.associative.replace(acquired_index, acquired_value)) |replaced| { return;
env.discard(replaced.key); };
env.discard(replaced.value);
errdefer context.env.release(value);
if (try table.associative.replace(index, value)) |replaced| {
context.env.release(replaced.key);
context.env.release(replaced.value);
} }
} }

View File

@ -192,17 +192,17 @@ pub const Root = struct {
return coral.io.allocate_one(self.arena.as_allocator(), stmt); return coral.io.allocate_one(self.arena.as_allocator(), stmt);
} }
pub fn free(self: *Root) void { pub fn deinit(self: *Root) void {
self.error_messages.free(); self.error_messages.deinit();
self.arena.free(); self.arena.deinit();
} }
pub fn make(allocator: coral.io.Allocator) coral.io.AllocationError!Root { pub fn init(allocator: coral.io.Allocator) coral.io.AllocationError!Root {
const arena_page_size = 4096; const arena_page_size = 4096;
return .{ return .{
.arena = coral.arena.Stacking.make(allocator, arena_page_size), .arena = coral.arena.Stacking.init(allocator, arena_page_size),
.error_messages = MessageList.make(allocator), .error_messages = MessageList.init(allocator),
.environment = .{}, .environment = .{},
}; };
} }

View File

@ -23,7 +23,7 @@ pub fn run_app(file_access: file.Access) void {
defer ext.SDL_Quit(); defer ext.SDL_Quit();
var script_env = kym.RuntimeEnv.make(heap.allocator, .{ var script_env = kym.RuntimeEnv.init(heap.allocator, 255, .{
.print = app.log_info, .print = app.log_info,
.print_error = app.log_fail, .print_error = app.log_fail,
.import_access = file_access, .import_access = file_access,
@ -31,7 +31,7 @@ pub fn run_app(file_access: file.Access) void {
return app.log_fail("failed to initialize script runtime"); return app.log_fail("failed to initialize script runtime");
}; };
defer script_env.free(); defer script_env.deinit();
var manifest = app.Manifest{}; var manifest = app.Manifest{};