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| {
const next_region = region.next;
@ -75,6 +75,15 @@ pub const Stacking = struct {
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 {
if (allocation) |buffer| {
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];
}
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];
}
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 {
if (math.checked_sub(self.values.len, count)) |updated_count| {
self.values = self.values[0 .. updated_count];
@ -26,16 +36,6 @@ pub fn Stack(comptime Value: type) type {
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 {
const grown_capacity = self.capacity + growth_amount;
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;
}
pub fn is_empty(self: Self) bool {
return self.values.len == 0;
}
pub fn make(allocator: io.Allocator) Self {
pub fn init(allocator: io.Allocator) Self {
return .{
.allocator = allocator,
.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 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.capacity = packed_size;
return self.values;
}
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;
}
pub fn free(self: *Self) void {
pub fn deinit(self: *Self) void {
if (self.entries.len == 0) {
return;
}
@ -185,6 +185,15 @@ pub fn Table(comptime Key: type, comptime Value: type, comptime Traits: type) ty
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 {
try self.rehash(load_max);
@ -235,23 +244,14 @@ pub fn Table(comptime Key: type, comptime Value: type, comptime Traits: type) ty
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 {
if (self.calculate_load_factor() <= max_load) {
return;
}
var table = make(self.allocator, self.traits);
var table = init(self.allocator, self.traits);
errdefer table.free();
errdefer table.deinit();
table.entries = allocate: {
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;
}

View File

@ -13,15 +13,15 @@ pub const Manifest = struct {
tick_rate: f32 = 60.0,
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: {
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)) {
break: get @intCast(fixed);
@ -33,9 +33,9 @@ pub const Manifest = struct {
const height = @as(u16, get: {
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)) {
break: get @intCast(fixed);
@ -47,18 +47,18 @@ pub const Manifest = struct {
const tick_rate = @as(f32, get: {
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;
});
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);
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");
name: *kym.RuntimeRef,
name: *kym.RuntimeObj,
arity: u8,
opcodes: OpcodeList,
lines: LineList,
cursor: usize,
constants: ConstList,
bindings: []?*kym.RuntimeRef,
bindings: []?*kym.RuntimeObj,
const Builtin = enum {
import,
@ -118,9 +118,9 @@ const Compiler = struct {
},
.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) {
try self.chunk.write(expression.line, .{.push_const = try self.declare_chunk(chunk)});
@ -193,7 +193,7 @@ const Compiler = struct {
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});
if (is_declaration_boxed(declaration_get.declaration)) {
@ -208,19 +208,19 @@ const Compiler = struct {
.declaration_set => |declaration_set| {
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)) {
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);
} else {
try self.compile_expression(environment, declaration_set.assign, null);
try self.chunk.write(expression.line, .{.set_local = index});
}
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.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);
@ -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);
@ -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);
@ -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);
@ -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);
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);
while (binding_index < environment.capture_count) : (binding_index += 1) {
@ -430,7 +430,7 @@ const Compiler = struct {
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) {
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);
@ -507,11 +507,33 @@ const OpcodeList = coral.list.Stack(Opcode);
const Self = @This();
pub fn dump(chunk: Self, env: *kym.RuntimeEnv) kym.RuntimeError!*kym.RuntimeRef {
var opcode_cursor = @as(u32, 0);
var buffer = coral.list.ByteStack.make(env.allocator);
pub fn deinit(self: *Self, env: *kym.RuntimeEnv) void {
while (self.constants.pop()) |constant| {
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);
@ -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_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.as_string();
coral.debug.assert(string != null);
const string = string_ref.is_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;
while (self.cursor < self.opcodes.values.len) : (self.cursor += 1) {
switch (self.opcodes.values[self.cursor]) {
.ret => break,
.pop => {
if (try env.pop_local()) |ref| {
env.discard(ref);
}
},
.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);
}
},
.pop => env.discard(),
.push_nil => _ = try env.push(null),
.push_true => _ = try env.new_boolean(true),
.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_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);
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| {
defer env.discard(value);
if (env.pop()) |object| {
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 => {
const value = try env.pop_local();
const value = env.pop();
defer {
if (value) |ref| {
env.discard(ref);
if (value) |object| {
env.release(object);
}
}
const boxable = try env.new_boxed(value);
errdefer env.discard(boxable);
try env.locals.push_one(boxable);
_ = try env.new_boxed(value);
},
.push_binding => |push_binding| {
try kym.assert(env, push_binding <= self.bindings.len);
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);
},
.push_binding => |push_binding| _ = try env.push(try self.get_binding(env, push_binding)),
.push_concat => |push_concat| _ = try env.concat(push_concat),
.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| {
const value = try env.pop_local();
const value = env.pop();
errdefer {
if (value) |ref| {
env.discard(ref);
if (value) |object| {
env.release(object);
}
}
const binding = &chunk.bindings[index];
if (binding.*) |*existing_binding| {
env.discard(existing_binding.*);
}
binding.* = value;
chunk.bindings[index] = value;
}
try env.locals.push_one(callable);
_ = try env.push(callable);
},
.push_builtin => |push_builtin| {
const builtin_syscall = try env.new_syscall(switch (push_builtin) {
.import => syscall_import,
.print => syscall_print,
.vec2 => syscall_vec2,
.vec3 => syscall_vec3,
});
.push_builtin => |push_builtin| _ = try env.new_syscall(switch (push_builtin) {
.import => syscall_import,
.print => syscall_print,
.vec2 => syscall_vec2,
.vec3 => syscall_vec3,
}),
errdefer env.discard(builtin_syscall);
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_local => |local_set| _ = try env.local_set(local_set, env.pop()),
.get_box => _ = try env.boxed_get(),
.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());
errdefer env.discard(value);
try env.set_boxed(box, value);
try env.boxed_set(value);
},
.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());
defer env.discard(indexable);
const value = try env.get(indexable, index);
errdefer {
if (value) |ref| {
env.discard(ref);
}
}
try env.locals.push_one(value);
_ = try env.index_get(index);
},
.set_dynamic => {
const value = try env.pop_local();
const value = env.pop();
defer {
if (value) |ref| {
env.discard(ref);
if (value) |object| {
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());
defer env.discard(indexable);
try env.set(indexable, index, value);
try env.index_set(index, value);
},
.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);
},
.call => |call| _ = try env.call(call),
.not => {
if (try env.pop_local()) |value| {
defer env.discard(value);
const object = try env.expect_object(env.pop());
try env.locals.push_one(try env.new_boolean(!value.is_truthy()));
} else {
try env.locals.push_one(try env.new_boolean(true));
}
defer env.release(object);
_ = try env.new_boolean(object.is_false());
},
.neg => {
const value = try env.expect(try env.pop_local());
defer env.discard(value);
try env.locals.push_one(try env.neg(value));
},
.neg => _ = try env.neg(),
.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());
defer env.discard(lhs);
try env.locals.push_one(try env.add(lhs, rhs));
_ = switch (try env.expect_numeric(addable)) {
.fixed => |fixed| try env.fixed_add(fixed),
.float => |float| try env.float_add(float),
.vector2 => |vector2| try env.vector2_add(vector2),
.vector3 => |vector3| try env.vector3_add(vector3),
};
},
.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());
defer env.discard(lhs);
try env.locals.push_one(try env.sub(lhs, rhs));
_ = switch (try env.expect_numeric(subtractable)) {
.fixed => |fixed| try env.fixed_subtract(fixed),
.float => |float| try env.float_subtract(float),
.vector2 => |vector2| try env.vector2_subtract(vector2),
.vector3 => |vector3| try env.vector3_subtract(vector3),
};
},
.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());
defer env.discard(lhs);
try env.locals.push_one(try env.mul(lhs, rhs));
_ = switch (try env.expect_numeric(multiplicable)) {
.fixed => |fixed| try env.fixed_multiply(fixed),
.float => |float| try env.float_multiply(float),
.vector2 => |vector2| try env.vector2_multiply(vector2),
.vector3 => |vector3| try env.vector3_multiply(vector3),
};
},
.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());
defer env.discard(lhs);
try env.locals.push_one(try env.div(lhs, rhs));
_ = switch (try env.expect_numeric(divisible)) {
.fixed => |fixed| try env.fixed_divide(fixed),
.float => |float| try env.float_divide(float),
.vector2 => |vector2| try env.vector2_divide(vector2),
.vector3 => |vector3| try env.vector3_divide(vector3),
};
},
.eql => {
if (try env.pop_local()) |rhs| {
env.discard(rhs);
if (env.pop()) |equatable| {
defer env.release(equatable);
if (try env.pop_local()) |lhs| {
env.discard(lhs);
try env.locals.push_one(try env.new_boolean(lhs.equals(rhs)));
} else {
try env.locals.push_one(try env.new_boolean(false));
}
_ = try env.equals_object(equatable);
} 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));
}
_ = try env.equals_nil();
}
},
.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());
defer env.discard(lhs);
try env.locals.push_one(try env.new_boolean(try env.compare(lhs, rhs) > 0));
_ = try env.compare_greater(comparable);
},
.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());
defer env.discard(lhs);
try env.locals.push_one(try env.new_boolean(try env.compare(lhs, rhs) < 0));
_ = try env.compare_less(comparable);
},
.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());
defer env.discard(lhs);
try env.locals.push_one(try env.new_boolean(try env.compare(lhs, rhs) >= 0));
_ = try env.compare_greater_equals(comparable);
},
.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());
defer env.discard(lhs);
try env.locals.push_one(try env.new_boolean(try env.compare(lhs, rhs) <= 0));
_ = try env.compare_less_equals(comparable);
},
.jf => |jf| {
if (try env.pop_local()) |condition| {
defer env.discard(condition);
if (env.pop()) |condition| {
defer env.release(condition);
if (!condition.is_truthy()) {
if (condition.is_false()) {
self.cursor = jf;
}
} else {
@ -1008,10 +866,10 @@ pub fn execute(self: *Self, env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.R
},
.jt => |jt| {
if (try env.pop_local()) |condition| {
defer env.discard(condition);
if (env.pop()) |condition| {
defer env.release(condition);
if (condition.is_truthy()) {
if (condition.is_true()) {
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 {
while (self.constants.pop()) |constant| {
env.discard(constant);
fn get_binding(self: *Self, env: *kym.RuntimeEnv, index: usize) kym.RuntimeError!?*kym.RuntimeObj {
if (index >= self.bindings.len) {
return env.raise(error.IllegalState, "invalid binding", .{});
}
self.constants.free();
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 = &.{};
return self.bindings[index];
}
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{
.name = try env.new_symbol(name),
.opcodes = OpcodeList.make(env.allocator),
.constants = ConstList.make(env.allocator),
.lines = LineList.make(env.allocator),
.name = (try env.new_symbol(name)).pop().?,
.opcodes = OpcodeList.init(env.allocator),
.constants = ConstList.init(env.allocator),
.lines = LineList.init(env.allocator),
.bindings = &.{},
.arity = environment.argument_count,
.cursor = 0,
@ -1065,38 +917,81 @@ pub fn make(env: *kym.RuntimeEnv, name: []const coral.io.Byte, environment: *con
return chunk;
}
fn syscall_import(env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
return env.import(file.Path.from(&.{try env.unwrap_string(try frame.expect_arg(env, 0))}));
fn syscall_import(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeObj {
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 {
env.print(try env.unwrap_string(try frame.expect_arg(env, 0)));
fn syscall_print(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeObj {
const string = (try (try env.arg_get(0)).to_string()).pop().?;
defer env.release(string);
env.print(string.is_string().?);
return null;
}
fn syscall_vec2(env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
const x = @as(f32, @floatCast(try env.unwrap_float(try frame.expect_arg(env, 0))));
fn syscall_vec2(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeObj {
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| {
return env.new_vector2(x, @floatCast(try env.unwrap_float(y)));
defer env.release(x);
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 {
const x = @as(f32, @floatCast(try env.unwrap_float(try frame.expect_arg(env, 0))));
fn syscall_vec3(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeObj {
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| {
return env.new_vector3(
x,
@floatCast(try env.unwrap_float(y)),
@floatCast(try env.unwrap_float(try frame.expect_arg(env, 2))),
);
defer env.release(x);
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_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{
@ -1107,16 +1002,16 @@ pub const typeinfo = &kym.Typeinfo{
.to_string = typeinfo_to_string,
};
fn typeinfo_call(env: *kym.RuntimeEnv, userdata: []coral.io.Byte, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
return @as(*Self, @ptrCast(@alignCast(userdata))).execute(env, frame);
fn typeinfo_call(context: kym.Typeinfo.CallContext) kym.RuntimeError!?*kym.RuntimeObj {
return @as(*Self, @ptrCast(@alignCast(context.userdata))).execute(context.env);
}
fn typeinfo_destruct(env: *kym.RuntimeEnv, userdata: []coral.io.Byte) void {
@as(*Self, @ptrCast(@alignCast(userdata))).free(env);
fn typeinfo_destruct(context: kym.Typeinfo.DestructContext) void {
@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 {
return env.to_string(@as(*Self, @ptrCast(@alignCast(userdata))).name);
fn typeinfo_to_string(context: kym.Typeinfo.ToStringContext) kym.RuntimeError!*kym.RuntimeObj {
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 {

View File

@ -5,41 +5,41 @@ const kym = @import("../kym.zig");
associative: RefTable,
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 {
pub const hash = kym.RuntimeRef.hash;
const RefTable = coral.map.Table(*kym.RuntimeObj, *kym.RuntimeObj, struct {
pub const hash = kym.RuntimeObj.hash;
pub const equals = kym.RuntimeRef.equals;
pub const equals = kym.RuntimeObj.equals;
});
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();
while (field_iterable.next()) |entry| {
env.discard(entry.key);
env.discard(entry.value);
env.release(entry.key);
env.release(entry.value);
}
}
self.associative.free();
self.associative.deinit();
while (self.contiguous.pop()) |value| {
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 .{
.associative = RefTable.make(env.allocator, .{}),
.contiguous = RefList.make(env.allocator),
.associative = RefTable.init(env.allocator, .{}),
.contiguous = RefList.init(env.allocator),
};
}
@ -51,41 +51,41 @@ pub const typeinfo = &kym.Typeinfo{
.set = typeinfo_set,
};
fn typeinfo_destruct(env: *kym.RuntimeEnv, userdata: []coral.io.Byte) void {
@as(*Self, @ptrCast(@alignCast(userdata))).free(env);
fn typeinfo_destruct(context: kym.Typeinfo.DestructContext) void {
@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 {
const table = @as(*Self, @ptrCast(@alignCast(userdata)));
const acquired_index = index.acquire();
fn typeinfo_get(context: kym.Typeinfo.GetContext) kym.RuntimeError!?*kym.RuntimeObj {
const table = @as(*Self, @ptrCast(@alignCast(context.userdata)));
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) {
// TODO: Negative indexing.
unreachable;
}
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| {
return value.acquire();
if (table.associative.lookup(index)) |value| {
return value;
}
return null;
}
fn typeinfo_set(env: *kym.RuntimeEnv, userdata: []coral.io.Byte, index: *const kym.RuntimeRef, value: ?*const kym.RuntimeRef) kym.RuntimeError!void {
const table = @as(*Self, @ptrCast(@alignCast(userdata)));
const acquired_index = index.acquire();
fn typeinfo_set(context: kym.Typeinfo.SetContext) kym.RuntimeError!void {
const table = @as(*Self, @ptrCast(@alignCast(context.userdata)));
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) {
// TODO: Negative indexing.
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)];
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);
maybe_replacing.* = value;
} else {
maybe_replacing.* = null;
}
return;
}
}
const acquired_value = (value orelse {
if (table.associative.remove(acquired_index)) |removed| {
env.discard(removed.key);
env.discard(removed.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);
}
return;
}).acquire();
};
errdefer env.discard(acquired_value);
errdefer context.env.release(value);
if (try table.associative.replace(acquired_index, acquired_value)) |replaced| {
env.discard(replaced.key);
env.discard(replaced.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);
}
pub fn free(self: *Root) void {
self.error_messages.free();
self.arena.free();
pub fn deinit(self: *Root) void {
self.error_messages.deinit();
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;
return .{
.arena = coral.arena.Stacking.make(allocator, arena_page_size),
.error_messages = MessageList.make(allocator),
.arena = coral.arena.Stacking.init(allocator, arena_page_size),
.error_messages = MessageList.init(allocator),
.environment = .{},
};
}

View File

@ -23,7 +23,7 @@ pub fn run_app(file_access: file.Access) void {
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_error = app.log_fail,
.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");
};
defer script_env.free();
defer script_env.deinit();
var manifest = app.Manifest{};