From c12e5ef48538d4466438131e7e6d6638245278de Mon Sep 17 00:00:00 2001 From: luccie Date: Tue, 26 Aug 2025 01:15:06 +0200 Subject: [PATCH] [MODS/PARSING]: Moved over to std.Io.Reader interface for upcoming zig update --- src/mods/Parser.zig | 67 +++++++++++++++++++++++---------------------- src/mods/ir.zig | 6 ++-- src/sideros.zig | 11 ++++---- 3 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/mods/Parser.zig b/src/mods/Parser.zig index 66dcbe8..d23126a 100644 --- a/src/mods/Parser.zig +++ b/src/mods/Parser.zig @@ -3,8 +3,7 @@ const vm = @import("vm.zig"); const IR = @import("ir.zig"); const Allocator = std.mem.Allocator; -bytes: []const u8, -byte_idx: usize, +reader: *std.Io.Reader, allocator: Allocator, types: []vm.Functype, @@ -27,6 +26,8 @@ pub const Error = error{ OutOfMemory, DivideBy0, Overflow, + ReadFailed, + EndOfStream, invalid_instruction, invalid_magic, invalid_version, @@ -51,15 +52,14 @@ pub const Error = error{ unterminated_wasm, }; -pub fn init(allocator: Allocator, bytes: []const u8) !Parser { +pub fn init(allocator: Allocator, reader: std.fs.File.Reader) !Parser { return .{ .elems = &.{}, .tables = &.{}, .parsedData = &.{}, .exported_memory = 0, .importCount = 0, - .bytes = bytes, - .byte_idx = 0, + .reader = @constCast(&reader.interface), .allocator = allocator, .types = &.{}, .functions = &.{}, @@ -103,18 +103,19 @@ pub fn module(self: *Parser) vm.Module { // TODO: This function should not exists fn warn(self: Parser, s: []const u8) void { - std.debug.print("[WARN]: Parsing of {s} unimplemented at byte index {d}\n", .{ s, self.byte_idx }); + std.debug.print("[WARN]: Parsing of {s} unimplemented at byte index {d}\n", .{ s, self.reader.seek }); } // TODO: remove peek? pub fn peek(self: Parser) ?u8 { - return if (self.byte_idx < self.bytes.len) self.bytes[self.byte_idx] else null; + return self.reader.peekByte() catch return null; } fn read(self: *Parser, n: usize) ![]const u8 { - if (self.byte_idx + n > self.bytes.len) return Error.unterminated_wasm; - defer self.byte_idx += n; - return self.bytes[self.byte_idx .. self.byte_idx + n]; + _ = self.reader.peek(n) catch { + return Error.unterminated_wasm; + }; + return try self.reader.readAlloc(self.allocator, n); } // ========== @@ -309,7 +310,7 @@ pub fn parseModule(self: *Parser) !void { if (!std.mem.eql(u8, try self.read(4), &.{ 0x00, 0x61, 0x73, 0x6d })) return Error.invalid_magic; if (!std.mem.eql(u8, try self.read(4), &.{ 0x01, 0x00, 0x00, 0x00 })) return Error.invalid_version; // TODO: Ensure only one section of each type (except for custom section), some code depends on it - while (self.byte_idx < self.bytes.len) { + while (self.reader.seek < self.reader.end) { try switch (try self.readByte()) { 0 => self.parseCustomsec(), 1 => self.parseTypesec(), @@ -343,7 +344,7 @@ fn parseCustomsec(self: *Parser) !void { fn parseTypesec(self: *Parser) !void { const size = try self.readU32(); - const end_idx = self.byte_idx + size; + const end_idx = self.reader.seek + size; const ft = try self.parseVector(Parser.parseFunctype); @@ -351,7 +352,7 @@ fn parseTypesec(self: *Parser) !void { self.types = ft; // TODO(ernesto): run this check not only on debug - std.debug.assert(self.byte_idx == end_idx); + std.debug.assert(self.reader.seek == end_idx); } pub const Import = struct { @@ -379,7 +380,7 @@ fn parseImport(self: *Parser) !Import { fn parseImportsec(self: *Parser) !void { const size = try self.readU32(); - const end_idx = self.byte_idx + size; + const end_idx = self.reader.seek + size; const imports = try self.parseVector(Parser.parseImport); @@ -423,12 +424,12 @@ fn parseImportsec(self: *Parser) !void { defer self.allocator.free(imports); // TODO: run this check not only on debug - std.debug.assert(self.byte_idx == end_idx); + std.debug.assert(self.reader.seek == end_idx); } fn parseFuncsec(self: *Parser) !void { const size = try self.readU32(); - const end_idx = self.byte_idx + size; + const end_idx = self.reader.seek + size; const types = try self.parseVector(Parser.readU32); defer self.allocator.free(types); @@ -449,7 +450,7 @@ fn parseFuncsec(self: *Parser) !void { std.debug.assert(types.len + self.importCount == self.functions.len); // TODO: run this check not only on debug - std.debug.assert(self.byte_idx == end_idx); + std.debug.assert(self.reader.seek == end_idx); } pub const Table = struct { @@ -464,7 +465,7 @@ fn parseTable(self: *Parser) !Table { fn parseTablesec(self: *Parser) !void { const size = try self.readU32(); - const end_idx = self.byte_idx + size; + const end_idx = self.reader.seek + size; const tables = try self.parseVector(Parser.parseTable); defer self.allocator.free(tables); @@ -476,12 +477,12 @@ fn parseTablesec(self: *Parser) !void { self.tables[i] = t.t; } - std.debug.assert(self.byte_idx == end_idx); + std.debug.assert(self.reader.seek == end_idx); } fn parseMemsec(self: *Parser) !void { const size = try self.readU32(); - const end_idx = self.byte_idx + size; + const end_idx = self.reader.seek + size; const mems = try self.parseVector(Parser.parseMemtype); defer self.allocator.free(mems); @@ -498,7 +499,7 @@ fn parseMemsec(self: *Parser) !void { } // TODO: run this check not only on debug - std.debug.assert(self.byte_idx == end_idx); + std.debug.assert(self.reader.seek == end_idx); } pub const Global = struct { @@ -515,7 +516,7 @@ fn parseGlobal(self: *Parser) !Global { fn parseGlobalsec(self: *Parser) !void { const size = try self.readU32(); - const end_idx = self.byte_idx + size; + const end_idx = self.reader.seek + size; const globals = try self.parseVector(Parser.parseGlobal); defer self.allocator.free(globals); @@ -530,7 +531,7 @@ fn parseGlobalsec(self: *Parser) !void { self.globalTypes[i] = global.t; } - std.debug.assert(self.byte_idx == end_idx); + std.debug.assert(self.reader.seek == end_idx); } pub const Export = struct { @@ -556,7 +557,7 @@ fn parseExport(self: *Parser) !Export { fn parseExportsec(self: *Parser) !void { const size = try self.readU32(); - const end_idx = self.byte_idx + size; + const end_idx = self.reader.seek + size; const exports = try self.parseVector(Parser.parseExport); defer { @@ -582,7 +583,7 @@ fn parseExportsec(self: *Parser) !void { } // TODO: run this check not only on debug - std.debug.assert(self.byte_idx == end_idx); + std.debug.assert(self.reader.seek == end_idx); } fn parseStartsec(self: *Parser) !void { @@ -636,7 +637,7 @@ fn parseElem(self: *Parser) !Elem { fn parseElemsec(self: *Parser) !void { const size = try self.readU32(); - const end_idx = self.byte_idx + size; + const end_idx = self.reader.seek + size; const elems = try self.parseVector(Parser.parseElem); defer self.allocator.free(elems); @@ -655,7 +656,7 @@ fn parseElemsec(self: *Parser) !void { } } - std.debug.assert(self.byte_idx == end_idx); + std.debug.assert(self.reader.seek == end_idx); } pub const Func = struct { @@ -675,7 +676,7 @@ fn parseLocal(self: *Parser) !Local { fn parseCode(self: *Parser) !Func { const size = try self.readU32(); - const end_idx = self.byte_idx + size; + const end_idx = self.reader.seek + size; const locals = try self.parseVector(Parser.parseLocal); defer self.allocator.free(locals); @@ -700,14 +701,14 @@ fn parseCode(self: *Parser) !Func { } // TODO: run this check not only on debug - std.debug.assert(self.byte_idx == end_idx); + std.debug.assert(self.reader.seek == end_idx); return func; } fn parseCodesec(self: *Parser) !void { const size = try self.readU32(); - const end_idx = self.byte_idx + size; + const end_idx = self.reader.seek + size; const codes = try self.parseVector(Parser.parseCode); defer self.allocator.free(codes); @@ -722,7 +723,7 @@ fn parseCodesec(self: *Parser) !void { } // TODO: run this check not only on debug - std.debug.assert(self.byte_idx == end_idx); + std.debug.assert(self.reader.seek == end_idx); } pub const Data = struct { @@ -747,14 +748,14 @@ fn parseData(self: *Parser) !Data { fn parseDatasec(self: *Parser) !void { const size = try self.readU32(); - const end_idx = self.byte_idx + size; + const end_idx = self.reader.seek + size; const datas = try self.parseVector(Parser.parseData); defer self.allocator.free(datas); for (datas) |data| { self.parsedData = try self.allocator.realloc(self.parsedData, @as(usize, @intCast(data.offsetVal.i32)) + data.data.len); @memcpy(self.parsedData[@as(usize, @intCast(data.offsetVal.i32))..@as(usize, @intCast(data.offsetVal.i32))+data.data.len], data.data); } - std.debug.assert(self.byte_idx == end_idx); + std.debug.assert(self.reader.seek == end_idx); } fn parseDatacountsec(self: *Parser) !void { diff --git a/src/mods/ir.zig b/src/mods/ir.zig index 7cc525a..3bfcc9b 100644 --- a/src/mods/ir.zig +++ b/src/mods/ir.zig @@ -649,7 +649,7 @@ const IRParserState = struct { 0xFD => self.parseVector(), 0xFC => self.parseMisc(), else => { - std.log.err("Invalid instruction {x} at position {d}\n", .{ b, self.parser.byte_idx }); + std.log.err("Invalid instruction {x} at position {d}\n", .{ b, self.parser.reader.seek }); return Parser.Error.invalid_instruction; }, }; @@ -697,7 +697,7 @@ const IRParserState = struct { }, 12...17 => @panic("UNIMPLEMENTED"), else => { - std.log.err("Invalid misc instruction {d} at position {d}\n", .{ n, self.parser.byte_idx }); + std.log.err("Invalid misc instruction {d} at position {d}\n", .{ n, self.parser.reader.seek }); return Parser.Error.invalid_instruction; }, }; @@ -845,7 +845,7 @@ const IRParserState = struct { try self.push(.vecinst, .{ .vector = .{ .opcode = @enumFromInt(n), .memarg = .{ .alignment = 0, .offset = 0 }, .laneidx = 0 } }); }, else => { - std.log.err("Invalid vector instruction {d} at position {d}\n", .{ n, self.parser.byte_idx }); + std.log.err("Invalid vector instruction {d} at position {d}\n", .{ n, self.parser.reader.seek }); return Parser.Error.invalid_instruction; }, }; diff --git a/src/sideros.zig b/src/sideros.zig index 616a953..9354ad3 100644 --- a/src/sideros.zig +++ b/src/sideros.zig @@ -73,13 +73,14 @@ fn loadMod(entry: std.fs.Dir.Entry) !void { std.debug.panic("Failed to delete {s} (reason: {any})", .{modDir, err}); }; defer file.close(); - const all = file.readToEndAlloc(allocator, 1_000_000) catch @panic("Unable to read main file"); - defer allocator.free(all); - var parser = mods.Parser.init(allocator, all) catch @panic("Failed to init parser"); + // TODO(luccie): Make this be able to construct a buffer for the whole file + const buffer = try allocator.alloc(u8, 1_000_000); + var parser = mods.Parser.init(allocator, file.reader(buffer)) catch @panic("Failed to init parser"); defer parser.deinit(); parser.parseModule() catch |err| { - std.debug.print("[ERROR]: error {any} at byte {x}(0x{x})\n", .{ err, parser.byte_idx, parser.bytes[parser.byte_idx] }); - return err; + // TODO(luccie): Find a better option for the expression `parser.reader.buffer[parser.reader.seek]` + std.debug.print("[ERROR]: error {any} at byte {x}(0x{x})\n", .{ err, parser.reader.seek, parser.reader.buffer[parser.reader.seek] }); + return err; }; const module = parser.module();