From fc1848d2c10a089d7a6878ee62482b299d39cb68 Mon Sep 17 00:00:00 2001 From: kayomn Date: Sun, 28 May 2023 12:44:32 +0000 Subject: [PATCH] Fix loading of script files in Ona --- source/coral/io.zig | 64 ++++++++++++++++++++++---- source/coral/list.zig | 83 ++++++---------------------------- source/ona/file.zig | 15 ++++-- source/ona/kym/Chunk.zig | 30 ++++++------ source/ona/kym/Environment.zig | 16 +++++-- source/ona/kym/types.zig | 6 --- 6 files changed, 108 insertions(+), 106 deletions(-) diff --git a/source/coral/io.zig b/source/coral/io.zig index d22dc51..9437ebf 100755 --- a/source/coral/io.zig +++ b/source/coral/io.zig @@ -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; diff --git a/source/coral/list.zig b/source/coral/list.zig index 01489a7..6cdcba2 100755 --- a/source/coral/list.zig +++ b/source/coral/list.zig @@ -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), - }; - } -}; diff --git a/source/ona/file.zig b/source/ona/file.zig index 2a983ba..cafa1e9 100644 --- a/source/ona/file.zig +++ b/source/ona/file.zig @@ -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; } diff --git a/source/ona/kym/Chunk.zig b/source/ona/kym/Chunk.zig index 4741068..fad11ce 100644 --- a/source/ona/kym/Chunk.zig +++ b/source/ona/kym/Chunk.zig @@ -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]; } diff --git a/source/ona/kym/Environment.zig b/source/ona/kym/Environment.zig index 7a788f0..860ffb9 100644 --- a/source/ona/kym/Environment.zig +++ b/source/ona/kym/Environment.zig @@ -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 = ""; 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, diff --git a/source/ona/kym/types.zig b/source/ona/kym/types.zig index e9c56df..d8f742e 100644 --- a/source/ona/kym/types.zig +++ b/source/ona/kym/types.zig @@ -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;