Refactor Kym #47
|
@ -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,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
pub const lina = @import("./gfx/lina.zig");
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
};
|
2389
source/ona/kym.zig
2389
source/ona/kym.zig
File diff suppressed because it is too large
Load Diff
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 = .{},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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{};
|
||||
|
||||
|
|
Loading…
Reference in New Issue