Merge pull request 'Refactor Kym' (#47) from kym-refactor into main
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			Reviewed-on: #47
This commit is contained in:
		
						commit
						ef537bef14
					
				| @ -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, |  | ||||||
| 		}; |  | ||||||
| 	} |  | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -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 { | ||||||
|  | |||||||
| @ -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; | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -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
									
								
							
							
						
						
									
										2
									
								
								source/ona/gfx.zig
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | |||||||
|  | 
 | ||||||
|  | pub const lina = @import("./gfx/lina.zig"); | ||||||
							
								
								
									
										181
									
								
								source/ona/gfx/lina.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								source/ona/gfx/lina.zig
									
									
									
									
									
										Normal 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, | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
							
								
								
									
										2319
									
								
								source/ona/kym.zig
									
									
									
									
									
								
							
							
						
						
									
										2319
									
								
								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"); | 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 { | ||||||
|  | |||||||
| @ -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); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -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 = .{}, | ||||||
| 		}; | 		}; | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -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{}; | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user