summaryrefslogtreecommitdiff
path: root/src/mods/Parser.zig
diff options
context:
space:
mode:
authorErnesto Lanchares <elancha98@proton.me>2025-04-04 18:34:58 +0200
committerErnesto Lanchares <elancha98@proton.me>2025-04-04 18:34:58 +0200
commit25e51f9aead0d1de6d6a9a9660d9363ef145316e (patch)
tree7d882523495f255792e661b8a68f9903c6bee2c1 /src/mods/Parser.zig
parent28420f53b06c7be0090ebbd4f242b11f976d6f64 (diff)
Modified how exports work and fixed memory leaks.
Now exports are already defined by the mods api (something like preinit, init, preframe, postframe, deinit should be enough functions). At the moment we only support preinit function.
Diffstat (limited to 'src/mods/Parser.zig')
-rw-r--r--src/mods/Parser.zig93
1 files changed, 72 insertions, 21 deletions
diff --git a/src/mods/Parser.zig b/src/mods/Parser.zig
index 544ef31..05824e3 100644
--- a/src/mods/Parser.zig
+++ b/src/mods/Parser.zig
@@ -7,10 +7,10 @@ bytes: []const u8,
byte_idx: usize,
allocator: Allocator,
-types: ?[]vm.Functype = null,
-functions: ?[]vm.Function = null,
-memory: ?Memtype = null,
-exports: std.StringHashMapUnmanaged(u32) = .{},
+types: []vm.Functype,
+functions: []vm.Function,
+memory: Memtype,
+exports: vm.Exports,
const Parser = @This();
@@ -33,10 +33,49 @@ pub const Error = error{
invalid_exportdesc,
double_else,
duplicated_funcsec,
+ duplicated_typesec,
unresolved_branch,
unterminated_wasm,
};
+pub fn init(allocator: Allocator, bytes: []const u8) !Parser {
+ return .{
+ .bytes = bytes,
+ .byte_idx = 0,
+ .allocator = allocator,
+ .types = &.{},
+ .functions = &.{},
+ .memory = .{
+ .lim = .{
+ .min = 0,
+ .max = 0,
+ },
+ },
+ .exports = .{},
+ };
+}
+
+pub fn deinit(self: Parser) void {
+ for (self.types) |t| {
+ self.allocator.free(t.parameters);
+ self.allocator.free(t.returns);
+ }
+ self.allocator.free(self.types);
+ self.allocator.free(self.functions);
+}
+
+pub fn module(self: *Parser) vm.Module {
+ defer self.functions = &.{};
+ return .{
+ .memory = .{
+ .min = self.memory.lim.min,
+ .max = self.memory.lim.max,
+ },
+ .functions = self.functions,
+ .exports = self.exports,
+ };
+}
+
// 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 });
@@ -231,7 +270,7 @@ fn parseGlobaltype(self: *Parser) !Globaltype {
// ===========
// NOTE: This should not return anything but modify IR
-pub fn parseModule(self: *Parser) !vm.Module {
+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
@@ -253,15 +292,6 @@ pub fn parseModule(self: *Parser) !vm.Module {
else => return Error.invalid_section,
};
}
-
- return .{
- .memory = .{
- .min = self.memory.?.lim.min,
- .max = self.memory.?.lim.max,
- },
- .exports = self.exports,
- .functions = self.functions.?,
- };
}
fn parseCustomsec(self: *Parser) !void {
@@ -275,6 +305,8 @@ fn parseTypesec(self: *Parser) !void {
const end_idx = self.byte_idx + size;
const ft = try self.parseVector(Parser.parseFunctype);
+
+ if (self.types.len != 0) return Error.duplicated_typesec;
self.types = ft;
// TODO(ernesto): run this check not only on debug
@@ -310,7 +342,7 @@ fn parseImportsec(self: *Parser) !void {
// TODO(ernesto): this should be used to do name resolution.
const imports = try self.parseVector(Parser.parseImport);
- _ = imports;
+ defer self.allocator.free(imports);
// TODO: run this check not only on debug
std.debug.assert(self.byte_idx == end_idx);
@@ -321,16 +353,22 @@ fn parseFuncsec(self: *Parser) !void {
const end_idx = self.byte_idx + size;
const types = try self.parseVector(Parser.readU32);
+ defer self.allocator.free(types);
- if (self.functions != null) return Error.duplicated_funcsec;
+ if (self.functions.len != 0) return Error.duplicated_funcsec;
self.functions = try self.allocator.alloc(vm.Function, types.len);
for (types, 0..) |t, i| {
- self.functions.?[i].func_type = self.types.?[t];
+ self.functions[i].func_type = .{
+ .parameters = try self.allocator.alloc(vm.Valtype, self.types[t].parameters.len),
+ .returns = try self.allocator.alloc(vm.Valtype, self.types[t].returns.len),
+ };
+ @memcpy(self.functions[i].func_type.parameters, self.types[t].parameters);
+ @memcpy(self.functions[i].func_type.returns, self.types[t].returns);
}
// TODO(ernesto): run this check not only in debug
- std.debug.assert(types.len == self.functions.?.len);
+ std.debug.assert(types.len == self.functions.len);
// TODO: run this check not only on debug
std.debug.assert(self.byte_idx == end_idx);
@@ -347,6 +385,7 @@ fn parseMemsec(self: *Parser) !void {
const end_idx = self.byte_idx + size;
const mems = try self.parseVector(Parser.parseMemtype);
+ defer self.allocator.free(mems);
if (mems.len == 0) {
// WTF?
} else if (mems.len == 1) {
@@ -391,9 +430,19 @@ fn parseExportsec(self: *Parser) !void {
const end_idx = self.byte_idx + size;
const exports = try self.parseVector(Parser.parseExport);
+ defer {
+ for (exports) |e| self.allocator.free(e.name);
+ self.allocator.free(exports);
+ }
for (exports) |e| {
switch (e.exportdesc) {
- .func => try self.exports.put(self.allocator, e.name, e.exportdesc.func),
+ .func => {
+ if (std.mem.eql(u8, e.name, "preinit")) {
+ self.exports.preinit = e.exportdesc.func;
+ } else {
+ std.log.warn("exported function {s} not supported\n", .{e.name});
+ }
+ },
else => std.debug.print("[WARN]: export ignored\n", .{}),
}
}
@@ -434,6 +483,7 @@ fn parseCode(self: *Parser) !Func {
const end_idx = self.byte_idx + size;
const locals = try self.parseVector(Parser.parseLocal);
+ defer self.allocator.free(locals);
var local_count: usize = 0;
for (locals) |l| {
local_count += l.n;
@@ -465,10 +515,11 @@ fn parseCodesec(self: *Parser) !void {
const end_idx = self.byte_idx + size;
const codes = try self.parseVector(Parser.parseCode);
+ defer self.allocator.free(codes);
// TODO: run this check not only on debug
- std.debug.assert(codes.len == self.functions.?.len);
+ std.debug.assert(codes.len == self.functions.len);
- for (codes, self.functions.?) |code, *f| {
+ for (codes, self.functions) |code, *f| {
f.typ = .{ .internal = .{
.locals = code.locals,
.ir = code.ir,