Fix loading of script files in Ona
continuous-integration/drone/push Build is passing Details

This commit is contained in:
kayomn 2023-05-28 12:44:32 +00:00
parent 1dc0c7f225
commit fc1848d2c1
6 changed files with 108 additions and 106 deletions

View File

@ -49,6 +49,11 @@ pub fn Functor(comptime Output: type, comptime Input: type) type {
pub const Reader = Functor(?usize, []u8);
pub const StreamError = error {
ReadFailure,
WriteFailure,
};
pub fn Tag(comptime Element: type) type {
return switch (@typeInfo(Element)) {
.Enum => |info| info.tag_type,
@ -57,18 +62,18 @@ pub fn Tag(comptime Element: type) type {
};
}
pub const WritableMemory = struct {
pub const FixedBuffer = struct {
slice: []u8,
pub fn as_writer(self: *WritableMemory) Writer {
pub fn as_writer(self: *FixedBuffer) Writer {
return Writer.bind(self, struct {
fn write(writable_memory: *WritableMemory, data: []const u8) ?usize {
fn write(writable_memory: *FixedBuffer, data: []const u8) ?usize {
return writable_memory.write(data);
}
}.write);
}
pub fn put(self: *WritableMemory, byte: u8) bool {
pub fn put(self: *FixedBuffer, byte: u8) bool {
if (self.slice.len == 0) {
return false;
}
@ -79,7 +84,7 @@ pub const WritableMemory = struct {
return true;
}
pub fn write(self: *WritableMemory, bytes: []const u8) usize {
pub fn write(self: *FixedBuffer, bytes: []const u8) usize {
const writable = math.min(self.slice.len, bytes.len);
copy(self.slice, bytes);
@ -90,6 +95,47 @@ pub const WritableMemory = struct {
}
};
pub const GrowingBuffer = struct {
allocator: Allocator,
appender: Appender,
const AppendOptions = struct {
allocator: Allocator,
bytes: []const u8,
};
const Appender = Functor(AllocationError!void, AppendOptions);
pub fn as_writer(self: *GrowingBuffer) Writer {
return Writer.bind(GrowingBuffer, self, struct {
fn write(growing_buffer: *GrowingBuffer, bytes: []const u8) ?usize {
growing_buffer.write(bytes) catch return null;
return bytes.len;
}
}.write);
}
pub fn bind(comptime State: type, allocator: Allocator, state: *State, comptime appender: fn (capture: *State, allocator: Allocator, bytes: []const u8) AllocationError!void) GrowingBuffer {
return .{
.appender = Appender.bind(State, state, struct {
fn append(self: *State, options: AppendOptions) AllocationError!void {
return appender(self, options.allocator, options.bytes);
}
}.append),
.allocator = allocator,
};
}
pub fn write(self: GrowingBuffer, bytes: []const u8) AllocationError!void {
return self.appender.invoke(.{
.allocator = self.allocator,
.bytes = bytes,
});
}
};
pub const Writer = Functor(?usize, []const u8);
pub fn allocate_many(comptime Type: type, amount: usize, allocator: Allocator) AllocationError![]Type {
@ -254,13 +300,13 @@ pub fn sentinel_index(comptime element: type, comptime sentinel: element, sequen
return index;
}
pub fn stream(output: Writer, input: Reader, buffer: []u8) ?u64 {
pub fn stream(output: Writer, input: Reader, buffer: []u8) StreamError!u64 {
var total_written: u64 = 0;
var read = input.invoke(buffer) orelse return null;
var read = input.invoke(buffer) orelse return error.ReadFailure;
while (read != 0) {
total_written += output.invoke(buffer[0..read]) orelse return null;
read = input.invoke(buffer) orelse return null;
total_written += output.invoke(buffer[0..read]) orelse return error.WriteFailure;
read = input.invoke(buffer) orelse return error.ReadFailure;
}
return total_written;

View File

@ -17,6 +17,19 @@ pub fn Stack(comptime Value: type) type {
///
const Self = @This();
///
/// Returns a [io.GrowableBuffer] bound to `self` and `allocator`.
///
/// The returned buffer may be used to write to the stack without needing to explicitly pass an allocator
/// context, as well decay further into a generic [io.Writer] type.
///
/// *Note* `allocator` must reference the same allocation strategy as the one originally used to initialize
/// `self`.
///
pub fn as_buffer(self: *Self, allocator: io.Allocator) io.GrowingBuffer {
return io.GrowingBuffer.bind(Self, allocator, self, push_all);
}
///
/// Clears all elements from `self` while preserving the current internal buffer.
///
@ -192,73 +205,3 @@ pub fn Stack(comptime Value: type) type {
}
};
}
///
/// Generic, byte-writable interface for all list types supported by the module.
///
/// As the type is only a thin wrapper around other resources, it does not manage any memory nor is it permitted to
/// outlive the resources it references.
///
pub const Writable = struct {
allocator: io.Allocator,
list: union (enum) {
stack: *ByteStack,
},
///
/// Stack of bytes.
///
const ByteStack = Stack(u8);
///
/// Binds and returns `self` as a [io.Writer].
///
pub fn as_writer(self: *Writable) io.Writer {
return io.Writer.bind(Writable, self, struct {
fn write(writable: *Writable, buffer: []const u8) ?usize {
writable.write(buffer) catch |allocation_error| switch (allocation_error) {
error.OutOfMemory => return null,
};
return buffer.len;
}
}.write);
}
///
/// Returns a new [Writable] from wrapping `stack` and `allocator`.
///
/// *Note* `allocator` must reference the same allocation strategy as the one originally used to initialize `stack`.
///
pub fn from_stack(allocator: io.Allocator, stack: *ByteStack) Writable {
return .{
.allocator = allocator,
.list = .{.stack = stack},
};
}
///
/// Attempts to write the singular `byte` to the list referenced by `self`.
///
/// The function returns [io.AllocationError] if `allocator` could not commit the memory required by the internal
/// list.
///
pub fn put(self: *Writable, byte: u8) io.AllocationError!void {
try switch (self.list) {
.stack => |stack| stack.push_one(self.allocator, byte),
};
}
///
/// Attempst to write all of `bytes` to the list referenced by `self`.
///
/// The function returns [io.AllocationError] if `allocator` could not commit the memory required by the internal
/// list.
///
pub fn write(self: *Writable, bytes: []const u8) io.AllocationError!void {
try switch (self.list) {
.stack => |stack| stack.push_all(self.allocator, bytes),
};
}
};

View File

@ -48,7 +48,7 @@ pub const Path = extern struct {
var path = Path{};
{
var writable_slice = coral.io.WritableMemory{.slice = &path.data};
var writable_slice = coral.io.FixedBuffer{.slice = &path.data};
for (components) |component| {
if (writable_slice.write(component) != component.len) {
@ -64,7 +64,7 @@ pub const Path = extern struct {
var path = Path{};
{
var writable = coral.io.WritableMemory{.slice = &path.data};
var writable = coral.io.FixedBuffer{.slice = &path.data};
var written = @as(usize, 0);
for (&self.data) |byte| {
@ -111,6 +111,14 @@ pub const ReadError = error {
};
pub const Readable = opaque {
pub fn as_reader(self: *Readable) coral.io.Reader {
return coral.io.Reader.bind(Readable, self, struct {
fn read(readable: *Readable, buffer: []u8) ?usize {
return readable.read(buffer) catch null;
}
}.read);
}
pub fn close(self: *Readable) void {
if (ext.SDL_RWclose(rw_ops_cast(self)) != 0) {
@panic("Failed to close file");
@ -121,8 +129,9 @@ pub const Readable = opaque {
ext.SDL_ClearError();
const bytes_read = ext.SDL_RWread(rw_ops_cast(self), buffer.ptr, @sizeOf(u8), buffer.len);
const error_message = ext.SDL_GetError();
if ((bytes_read == 0) and (ext.SDL_GetError() != null)) {
if (bytes_read == 0 and error_message != null and error_message.* != 0) {
return error.FileUnavailable;
}

View File

@ -10,7 +10,7 @@ const tokens = @import("./tokens.zig");
env: *Environment,
message_name_len: usize,
message_buffer: Buffer,
message_data: Buffer,
bytecode_buffer: Buffer,
const Buffer = coral.list.Stack(u8);
@ -45,8 +45,8 @@ const Opcode = enum (u8) {
const Self = @This();
fn clear_error_details(self: *Self) void {
coral.debug.assert(self.message_buffer.values.len >= self.message_name_len);
coral.debug.assert(self.message_buffer.drop(self.message_buffer.values.len - self.message_name_len));
coral.debug.assert(self.message_data.values.len >= self.message_name_len);
coral.debug.assert(self.message_data.drop(self.message_data.values.len - self.message_name_len));
}
pub fn compile(self: *Self, data: []const u8) types.RuntimeError!void {
@ -75,10 +75,10 @@ pub fn compile(self: *Self, data: []const u8) types.RuntimeError!void {
.invalid => |invalid| {
self.clear_error_details();
try self.message_buffer.push_all(self.env.allocator, "@(");
try self.message_data.push_all(self.env.allocator, "@(");
var writable_message = coral.list.Writable.from_stack(self.env.allocator, &self.message_buffer);
const message_writer = writable_message.as_writer();
var message_buffer = self.message_data.as_buffer(self.env.allocator);
const message_writer = message_buffer.as_writer();
coral.utf8.print_int(@typeInfo(usize).Int, message_writer, tokenizer.lines_stepped) catch {
return error.OutOfMemory;
@ -175,7 +175,7 @@ pub fn compile_expression(self: *Self, expression: ast.Expression) types.Runtime
pub fn deinit(self: *Self) void {
self.bytecode_buffer.deinit(self.env.allocator);
self.message_buffer.deinit(self.env.allocator);
self.message_data.deinit(self.env.allocator);
self.message_name_len = 0;
}
@ -197,9 +197,9 @@ pub fn emit_opcode(self: *Self, opcode: Opcode) coral.io.AllocationError!void {
}
pub fn error_details(self: Self) []const u8 {
coral.debug.assert(self.message_buffer.values.len >= self.message_name_len);
coral.debug.assert(self.message_data.values.len >= self.message_name_len);
return self.message_buffer.values[self.message_name_len .. ];
return self.message_data.values[self.message_name_len .. ];
}
pub fn init(env: *Environment, chunk_name: []const u8) coral.io.AllocationError!Self {
@ -207,15 +207,15 @@ pub fn init(env: *Environment, chunk_name: []const u8) coral.io.AllocationError!
errdefer bytecode_buffer.deinit(env.allocator);
var message_buffer = try Buffer.init(env.allocator, chunk_name.len);
var message_data = try Buffer.init(env.allocator, chunk_name.len);
errdefer message_buffer.deinit(env.allocator);
errdefer message_data.deinit(env.allocator);
message_buffer.push_all(env.allocator, chunk_name) catch unreachable;
message_data.push_all(env.allocator, chunk_name) catch unreachable;
return Self{
.env = env,
.message_buffer = message_buffer,
.message_data = message_data,
.bytecode_buffer = bytecode_buffer,
.message_name_len = chunk_name.len,
};
@ -230,7 +230,7 @@ pub fn intern(self: *Self, string: []const u8) coral.io.AllocationError!types.Ob
}
pub fn name(self: Self) []const u8 {
coral.debug.assert(self.message_buffer.values.len >= self.message_name_len);
coral.debug.assert(self.message_data.values.len >= self.message_name_len);
return self.message_buffer.values[0 .. self.message_name_len];
return self.message_data.values[0 .. self.message_name_len];
}

View File

@ -26,7 +26,7 @@ pub const DataSource = struct {
data: []const u8,
};
pub const ExecuteFileError = file.System.OpenError || file.ReadError || types.CompileError;
pub const ExecuteFileError = file.System.OpenError || coral.io.StreamError || file.ReadError || types.RuntimeError;
pub const InitOptions = struct {
values_max: u32,
@ -201,7 +201,7 @@ pub fn discard(self: *Self, val: types.Val) void {
}
}
pub fn execute_data(self: *Self, source: DataSource) ExecuteFileError!types.Val {
pub fn execute_data(self: *Self, source: DataSource) types.RuntimeError!types.Val {
const typeid = "<chunk>";
const Behaviors = struct {
@ -235,10 +235,20 @@ pub fn execute_file(self: *Self, fs: file.System, file_path: file.Path) ExecuteF
defer readable_file.close();
var file_source = try coral.list.Stack(u8).init(self.allocator, (try fs.query_info(file_path)).size);
const file_size = (try fs.query_info(file_path)).size;
var file_source = try coral.list.Stack(u8).init(self.allocator, file_size);
defer file_source.deinit(self.allocator);
{
var file_buffer = file_source.as_buffer(self.allocator);
var stream_buffer = [_]u8{0} ** 4096;
if ((try coral.io.stream(file_buffer.as_writer(), readable_file.as_reader(), &stream_buffer)) != file_size) {
return error.ReadFailure;
}
}
return try self.execute_data(.{
.name = try file_path.to_string(),
.data = file_source.values,

View File

@ -4,12 +4,6 @@ pub const CheckError = error {
CheckFailed
};
pub const CompileError = coral.io.AllocationError || RuntimeError || error {
UnexpectedEnd,
UnexpectedToken,
UndefinedLocal,
};
pub const Float = f32;
pub const Integer = i32;