From eace09d5d0fece311f47eadf02a580962583c8c9 Mon Sep 17 00:00:00 2001 From: radarroark <122068506+radarroark@users.noreply.github.com> Date: Sat, 8 Jul 2023 15:14:01 -0400 Subject: [PATCH] fixes for compatibility with zig 0.11.0 (#190) Not ready to merge. After these changes, the modules can individually build with 0.11.0-dev.3132+465272921 but the testrunner build command fails: ``` $ zig build --build-file test/testrunner/build.zig --prefix ./ zig build-exe testrunner Debug native: error: warning: FileNotFound: test/testrunner/src/main.zig error: FileNotFound ``` Yours truly looked into it and found that it is a build system bug. Here's the fix: https://github.com/ziglang/zig/pull/15717 Hopefully that can get into the release. Shake and bake! --------- Co-authored-by: Malcolm Still --- .github/workflows/test.yaml | 30 ++-- .gitignore | 1 + README.md | 5 +- build.zig | 23 ++- examples/fib/build.zig | 25 ++-- src/instance.zig | 20 +-- src/instance/vm.zig | 231 ++++++++++++++--------------- src/module.zig | 32 ++-- src/module/parser.zig | 12 +- src/module/validator.zig | 6 +- src/store/function.zig | 4 +- src/store/memory.zig | 31 ++-- test/fuzzer/build.zig | 26 ++-- test/fuzzer/src/fuzzer.zig | 6 +- test/interface/build.zig | 26 ++-- test/interface/src/interface.zig | 4 +- test/parsecheck/build.zig | 26 ++-- test/parsecheck/src/parsecheck.zig | 2 +- test/run-generated.sh | 2 +- test/testrunner/build.zig | 26 ++-- test/testrunner/src/testrunner.zig | 178 +++++++++++++++------- 21 files changed, 395 insertions(+), 321 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b27c660f..7e0385f4 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v2 - uses: goto-bus-stop/setup-zig@v1 with: - version: 0.10.0 + version: master - run: zig build test testsuite: runs-on: ubuntu-latest @@ -24,33 +24,39 @@ jobs: - uses: actions/checkout@v2 - uses: goto-bus-stop/setup-zig@v1 with: - version: 0.10.0 - - run: zig build --build-file test/testrunner/build.zig --prefix ./ - - run: cp bin/testrunner testrunner - - run: cp test/testsuite-generated/* ./ - - run: bash test/run-generated.sh + version: master + - name: Build test runner + working-directory: ./test/testrunner + run: zig build --prefix ./ + - name: Run testsuite + run: bash test/run-generated.sh parsecheck: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: goto-bus-stop/setup-zig@v1 with: - version: 0.10.0 - - run: zig build --build-file test/parsecheck/build.zig --prefix ./ - - run: bin/parsecheck test/testsuite-generated + version: master + - name: Build parsecheck + working-directory: ./test/parsecheck + run: zig build --prefix ./ + - name: Run parse check + run: test/parsecheck/bin/parsecheck test/testsuite-generated build_interface: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: goto-bus-stop/setup-zig@v1 with: - version: 0.10.0 - - run: zig build --build-file test/interface/build.zig + version: master + - name: Build interface + working-directory: ./test/interface + run: zig build lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: goto-bus-stop/setup-zig@v1 with: - version: 0.10.0 + version: master - run: zig fmt --check src/*.zig diff --git a/.gitignore b/.gitignore index 4c82b07c..e773336b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ zig-cache zig-out +test/testrunner/bin \ No newline at end of file diff --git a/README.md b/README.md index 36334629..ff8658a4 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ pub fn main() !void { ### Compile-time -- Zig 0.10.0 +- Zig 0.11 (master) ### Run-time @@ -80,7 +80,8 @@ pub fn main() !void { 1. Build the test runner ``` -zig build --build-file test/testrunner/build.zig --prefix ./ +cd test/testrunner +zig build --prefix ./ ``` 2. Run diff --git a/build.zig b/build.zig index 0c320bb1..0bfb0867 100644 --- a/build.zig +++ b/build.zig @@ -1,14 +1,23 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - const mode = b.standardReleaseOptions(); - const lib = b.addStaticLibrary("zware", "src/main.zig"); - lib.setBuildMode(mode); - lib.install(); + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); - var main_tests = b.addTest("src/main.zig"); - main_tests.setBuildMode(mode); + const lib = b.addStaticLibrary(.{ + .name = "zware", + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + b.installArtifact(lib); + const main_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/main.zig" }, + .optimize = optimize, + }); + + const run_main_tests = b.addRunArtifact(main_tests); const test_step = b.step("test", "Run library tests"); - test_step.dependOn(&main_tests.step); + test_step.dependOn(&run_main_tests.step); } diff --git a/examples/fib/build.zig b/examples/fib/build.zig index 75d8fc59..c7043594 100644 --- a/examples/fib/build.zig +++ b/examples/fib/build.zig @@ -1,23 +1,20 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - // Standard target options allows the person running `zig build` to choose - // what target to build for. Here we do not override the defaults, which - // means any target is allowed, and the default is native. Other options - // for restricting supported target set are available. const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); - // Standard release options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); + const exe = b.addExecutable(.{ + .name = "fib", + .root_source_file = .{ .path = "src/fib.zig" }, + .target = target, + .optimize = optimize, + }); + exe.addAnonymousModule("zware", .{ + .source_file = .{ .path = "../../src/main.zig" }, + }); - const exe = b.addExecutable("fib", "src/fib.zig"); - exe.addPackagePath("zware", "../../src/main.zig"); - exe.setTarget(target); - exe.setBuildMode(mode); - exe.install(); - - const run_cmd = exe.run(); + const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { run_cmd.addArgs(args); diff --git a/src/instance.zig b/src/instance.zig index fb7ce418..5193c17b 100644 --- a/src/instance.zig +++ b/src/instance.zig @@ -141,7 +141,7 @@ pub const Instance = struct { // // For 2, we need to add the function to the store const imported_function_count = self.funcaddrs.items.len; - for (self.module.functions.list.items) |function_def, i| { + for (self.module.functions.list.items, 0..) |function_def, i| { if (function_def.import) |_| { // Check that the function defintion (which this module expects) // is the same as the function in the store @@ -174,7 +174,7 @@ pub const Instance = struct { } fn instantiateGlobals(self: *Instance) !void { - for (self.module.globals.list.items) |global_def, i| { + for (self.module.globals.list.items, 0..) |global_def, i| { if (global_def.import != null) { const imported_global = try self.getGlobal(i); if (imported_global.mutability != global_def.mutability) return error.MismatchedMutability; @@ -192,7 +192,7 @@ pub const Instance = struct { } fn instantiateMemories(self: *Instance) !void { - for (self.module.memories.list.items) |memtype, i| { + for (self.module.memories.list.items, 0..) |memtype, i| { if (memtype.import != null) { const imported_mem = try self.getMemory(i); // Use the current size of the imported mem as min (rather than imported_mem.min). See https://github.com/WebAssembly/spec/pull/1293 @@ -205,7 +205,7 @@ pub const Instance = struct { } fn instantiateTables(self: *Instance) !void { - for (self.module.tables.list.items) |tabletype, i| { + for (self.module.tables.list.items, 0..) |tabletype, i| { if (tabletype.import != null) { const imported_table = try self.getTable(i); if (imported_table.reftype != tabletype.reftype) return error.ImportedTableRefTypeMismatch; @@ -224,7 +224,7 @@ pub const Instance = struct { var data = try self.store.data(dataddr); // TODO: Do we actually need to copy the data or just close over module bytes? - for (datatype.data) |byte, j| { + for (datatype.data, 0..) |byte, j| { try data.set(j, byte); } @@ -248,9 +248,9 @@ pub const Instance = struct { try self.elemaddrs.append(elemaddr); var elem = try self.store.elem(elemaddr); - for (self.module.element_init_offsets.items[elemtype.init .. elemtype.init + elemtype.count]) |expr, j| { + for (self.module.element_init_offsets.items[elemtype.init .. elemtype.init + elemtype.count], 0..) |expr, j| { const funcaddr = try self.invokeExpression(expr, u32, .{}); - try elem.set(@intCast(u32, j), funcaddr); + try elem.set(@intCast(j), funcaddr); } if (elemtype.mode != .Passive) { @@ -264,8 +264,8 @@ pub const Instance = struct { const index = math.add(u32, offset, elemtype.count) catch return error.OutOfBoundsMemoryAccess; if (index > table.size()) return error.OutOfBoundsMemoryAccess; - for (elem.elem) |funcaddr, i| { - try table.set(@intCast(u32, offset + i), funcaddr); + for (elem.elem, 0..) |funcaddr, i| { + try table.set(@intCast(offset + i), funcaddr); } } } @@ -329,7 +329,7 @@ pub const Instance = struct { try vm.invoke(f.start); // 9. - for (out) |_, out_index| { + for (out, 0..) |_, out_index| { out[out_index] = vm.popOperand(u64); } }, diff --git a/src/instance/vm.zig b/src/instance/vm.zig index 6cf14017..f20027a2 100644 --- a/src/instance/vm.zig +++ b/src/instance/vm.zig @@ -61,7 +61,7 @@ pub const VirtualMachine = struct { pub fn invoke(self: *VirtualMachine, ip: usize) !void { const instr = self.inst.module.parsed_code.items[ip]; - try @call(.{}, lookup[@enumToInt(instr)], .{ self, ip, self.inst.module.parsed_code.items }); + try @call(.auto, lookup[@intFromEnum(instr)], .{ self, ip, self.inst.module.parsed_code.items }); } const InstructionFunction = *const fn (*VirtualMachine, usize, []Rr) WasmError!void; @@ -88,7 +88,7 @@ pub const VirtualMachine = struct { inline fn dispatch(self: *VirtualMachine, next_ip: usize, code: []Rr) WasmError!void { const next_instr = code[next_ip]; - return try @call(.{ .modifier = .always_tail }, lookup[@enumToInt(next_instr)], .{ self, next_ip, code }); + return try @call(.always_tail, lookup[@intFromEnum(next_instr)], .{ self, next_ip, code }); } pub const REF_NULL: u64 = 0xFFFF_FFFF_FFFF_FFFF; @@ -665,7 +665,7 @@ pub const VirtualMachine = struct { const meta = code[ip].@"i32.store8"; const memory = try self.inst.getMemory(0); - const value = @truncate(u8, self.popOperand(u32)); + const value: u8 = @truncate(self.popOperand(u32)); const address = self.popOperand(u32); try memory.write(u8, meta.offset, address, value); @@ -677,7 +677,7 @@ pub const VirtualMachine = struct { const meta = code[ip].@"i32.store16"; const memory = try self.inst.getMemory(0); - const value = @truncate(u16, self.popOperand(u32)); + const value: u16 = @truncate(self.popOperand(u32)); const address = self.popOperand(u32); try memory.write(u16, meta.offset, address, value); @@ -689,7 +689,7 @@ pub const VirtualMachine = struct { const meta = code[ip].@"i64.store8"; const memory = try self.inst.getMemory(0); - const value = @truncate(u8, self.popOperand(u64)); + const value: u8 = @truncate(self.popOperand(u64)); const address = self.popOperand(u32); try memory.write(u8, meta.offset, address, value); @@ -701,7 +701,7 @@ pub const VirtualMachine = struct { const meta = code[ip].@"i64.store16"; const memory = try self.inst.getMemory(0); - const value = @truncate(u16, self.popOperand(u64)); + const value: u16 = @truncate(self.popOperand(u64)); const address = self.popOperand(u32); try memory.write(u16, meta.offset, address, value); @@ -713,7 +713,7 @@ pub const VirtualMachine = struct { const meta = code[ip].@"i64.store32"; const memory = try self.inst.getMemory(0); - const value = @truncate(u32, self.popOperand(u64)); + const value: u32 = @truncate(self.popOperand(u64)); const address = self.popOperand(u32); try memory.write(u32, meta.offset, address, value); @@ -724,7 +724,7 @@ pub const VirtualMachine = struct { fn @"memory.size"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const memory = try self.inst.getMemory(0); - self.pushOperandNoCheck(u32, @intCast(u32, memory.size())); + self.pushOperandNoCheck(u32, @as(u32, @intCast(memory.size()))); return dispatch(self, ip + 1, code); } @@ -734,7 +734,7 @@ pub const VirtualMachine = struct { const num_pages = self.popOperand(u32); if (memory.grow(num_pages)) |old_size| { - self.pushOperandNoCheck(u32, @intCast(u32, old_size)); + self.pushOperandNoCheck(u32, @as(u32, @intCast(old_size))); } else |_| { self.pushOperandNoCheck(i32, @as(i32, -1)); } @@ -1534,7 +1534,7 @@ pub const VirtualMachine = struct { self.pushOperandNoCheck(f32, c2); } } else { - self.pushOperandNoCheck(f32, math.min(c1, c2)); + self.pushOperandNoCheck(f32, @min(c1, c2)); } return dispatch(self, ip + 1, code); @@ -1560,7 +1560,7 @@ pub const VirtualMachine = struct { self.pushOperandNoCheck(f32, c1); } } else { - self.pushOperandNoCheck(f32, math.max(c1, c2)); + self.pushOperandNoCheck(f32, @max(c1, c2)); } return dispatch(self, ip + 1, code); @@ -1697,7 +1697,7 @@ pub const VirtualMachine = struct { self.pushOperandNoCheck(f64, c2); } } else { - self.pushOperandNoCheck(f64, math.min(c1, c2)); + self.pushOperandNoCheck(f64, @min(c1, c2)); } return dispatch(self, ip + 1, code); @@ -1719,7 +1719,7 @@ pub const VirtualMachine = struct { self.pushOperandNoCheck(f64, c1); } } else { - self.pushOperandNoCheck(f64, math.max(c1, c2)); + self.pushOperandNoCheck(f64, @max(c1, c2)); } return dispatch(self, ip + 1, code); @@ -1741,7 +1741,7 @@ pub const VirtualMachine = struct { fn @"i32.wrap_i64"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i64); - self.pushOperandNoCheck(i32, @truncate(i32, c1)); + self.pushOperandNoCheck(i32, @as(i32, @truncate(c1))); return dispatch(self, ip + 1, code); } @@ -1753,10 +1753,10 @@ pub const VirtualMachine = struct { const trunc = @trunc(c1); - if (trunc >= @intToFloat(f32, math.maxInt(i32))) return error.Overflow; - if (trunc < @intToFloat(f32, math.minInt(i32))) return error.Overflow; + if (trunc >= @as(f32, @floatFromInt(math.maxInt(i32)))) return error.Overflow; + if (trunc < @as(f32, @floatFromInt(math.minInt(i32)))) return error.Overflow; - self.pushOperandNoCheck(i32, @floatToInt(i32, trunc)); + self.pushOperandNoCheck(i32, @as(i32, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -1768,10 +1768,10 @@ pub const VirtualMachine = struct { const trunc = @trunc(c1); - if (trunc >= @intToFloat(f32, math.maxInt(u32))) return error.Overflow; - if (trunc < @intToFloat(f32, math.minInt(u32))) return error.Overflow; + if (trunc >= @as(f32, @floatFromInt(math.maxInt(u32)))) return error.Overflow; + if (trunc < @as(f32, @floatFromInt(math.minInt(u32)))) return error.Overflow; - self.pushOperandNoCheck(u32, @floatToInt(u32, trunc)); + self.pushOperandNoCheck(u32, @as(u32, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -1783,10 +1783,10 @@ pub const VirtualMachine = struct { const trunc = @trunc(c1); - if (trunc > @intToFloat(f64, math.maxInt(i32))) return error.Overflow; - if (trunc < @intToFloat(f64, math.minInt(i32))) return error.Overflow; + if (trunc > @as(f64, @floatFromInt(math.maxInt(i32)))) return error.Overflow; + if (trunc < @as(f64, @floatFromInt(math.minInt(i32)))) return error.Overflow; - self.pushOperandNoCheck(i32, @floatToInt(i32, trunc)); + self.pushOperandNoCheck(i32, @as(i32, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -1798,10 +1798,10 @@ pub const VirtualMachine = struct { const trunc = @trunc(c1); - if (trunc > @intToFloat(f64, math.maxInt(u32))) return error.Overflow; - if (trunc < @intToFloat(f64, math.minInt(u32))) return error.Overflow; + if (trunc > @as(f64, @floatFromInt(math.maxInt(u32)))) return error.Overflow; + if (trunc < @as(f64, @floatFromInt(math.minInt(u32)))) return error.Overflow; - self.pushOperandNoCheck(u32, @floatToInt(u32, trunc)); + self.pushOperandNoCheck(u32, @as(u32, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -1809,7 +1809,7 @@ pub const VirtualMachine = struct { fn @"i64.extend_i32_s"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i64); - self.pushOperandNoCheck(i64, @truncate(i32, c1)); + self.pushOperandNoCheck(i64, @as(i32, @truncate(c1))); return dispatch(self, ip + 1, code); } @@ -1817,7 +1817,7 @@ pub const VirtualMachine = struct { fn @"i64.extend_i32_u"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(u64); - self.pushOperandNoCheck(u64, @truncate(u32, c1)); + self.pushOperandNoCheck(u64, @as(u32, @truncate(c1))); return dispatch(self, ip + 1, code); } @@ -1829,10 +1829,10 @@ pub const VirtualMachine = struct { const trunc = @trunc(c1); - if (trunc >= @intToFloat(f32, math.maxInt(i64))) return error.Overflow; - if (trunc < @intToFloat(f32, math.minInt(i64))) return error.Overflow; + if (trunc >= @as(f32, @floatFromInt(math.maxInt(i64)))) return error.Overflow; + if (trunc < @as(f32, @floatFromInt(math.minInt(i64)))) return error.Overflow; - self.pushOperandNoCheck(i64, @floatToInt(i64, trunc)); + self.pushOperandNoCheck(i64, @as(i64, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -1844,10 +1844,10 @@ pub const VirtualMachine = struct { const trunc = @trunc(c1); - if (trunc >= @intToFloat(f32, math.maxInt(u64))) return error.Overflow; - if (trunc < @intToFloat(f32, math.minInt(u64))) return error.Overflow; + if (trunc >= @as(f32, @floatFromInt(math.maxInt(u64)))) return error.Overflow; + if (trunc < @as(f32, @floatFromInt(math.minInt(u64)))) return error.Overflow; - self.pushOperandNoCheck(u64, @floatToInt(u64, trunc)); + self.pushOperandNoCheck(u64, @as(u64, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -1859,10 +1859,10 @@ pub const VirtualMachine = struct { const trunc = @trunc(c1); - if (trunc >= @intToFloat(f64, math.maxInt(i64))) return error.Overflow; - if (trunc < @intToFloat(f64, math.minInt(i64))) return error.Overflow; + if (trunc >= @as(f64, @floatFromInt(math.maxInt(i64)))) return error.Overflow; + if (trunc < @as(f64, @floatFromInt(math.minInt(i64)))) return error.Overflow; - self.pushOperandNoCheck(i64, @floatToInt(i64, trunc)); + self.pushOperandNoCheck(i64, @as(i64, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -1874,10 +1874,10 @@ pub const VirtualMachine = struct { const trunc = @trunc(c1); - if (trunc >= @intToFloat(f64, math.maxInt(u64))) return error.Overflow; - if (trunc < @intToFloat(f64, math.minInt(u64))) return error.Overflow; + if (trunc >= @as(f64, @floatFromInt(math.maxInt(u64)))) return error.Overflow; + if (trunc < @as(f64, @floatFromInt(math.minInt(u64)))) return error.Overflow; - self.pushOperandNoCheck(u64, @floatToInt(u64, trunc)); + self.pushOperandNoCheck(u64, @as(u64, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -1885,7 +1885,7 @@ pub const VirtualMachine = struct { fn @"f32.convert_i32_s"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i32); - self.pushOperandNoCheck(f32, @intToFloat(f32, c1)); + self.pushOperandNoCheck(f32, @as(f32, @floatFromInt(c1))); return dispatch(self, ip + 1, code); } @@ -1893,7 +1893,7 @@ pub const VirtualMachine = struct { fn @"f32.convert_i32_u"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(u32); - self.pushOperandNoCheck(f32, @intToFloat(f32, c1)); + self.pushOperandNoCheck(f32, @as(f32, @floatFromInt(c1))); return dispatch(self, ip + 1, code); } @@ -1901,7 +1901,7 @@ pub const VirtualMachine = struct { fn @"f32.convert_i64_s"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i64); - self.pushOperandNoCheck(f32, @intToFloat(f32, c1)); + self.pushOperandNoCheck(f32, @as(f32, @floatFromInt(c1))); return dispatch(self, ip + 1, code); } @@ -1909,7 +1909,7 @@ pub const VirtualMachine = struct { fn @"f32.convert_i64_u"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(u64); - self.pushOperandNoCheck(f32, @intToFloat(f32, c1)); + self.pushOperandNoCheck(f32, @as(f32, @floatFromInt(c1))); return dispatch(self, ip + 1, code); } @@ -1917,7 +1917,7 @@ pub const VirtualMachine = struct { fn @"f32.demote_f64"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(f64); - self.pushOperandNoCheck(f32, @floatCast(f32, c1)); + self.pushOperandNoCheck(f32, @as(f32, @floatCast(c1))); return dispatch(self, ip + 1, code); } @@ -1925,7 +1925,7 @@ pub const VirtualMachine = struct { fn @"f64.convert_i32_s"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i32); - self.pushOperandNoCheck(f64, @intToFloat(f64, c1)); + self.pushOperandNoCheck(f64, @as(f64, @floatFromInt(c1))); return dispatch(self, ip + 1, code); } @@ -1933,7 +1933,7 @@ pub const VirtualMachine = struct { fn @"f64.convert_i32_u"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(u32); - self.pushOperandNoCheck(f64, @intToFloat(f64, c1)); + self.pushOperandNoCheck(f64, @as(f64, @floatFromInt(c1))); return dispatch(self, ip + 1, code); } @@ -1941,7 +1941,7 @@ pub const VirtualMachine = struct { fn @"f64.convert_i64_s"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i64); - self.pushOperandNoCheck(f64, @intToFloat(f64, c1)); + self.pushOperandNoCheck(f64, @as(f64, @floatFromInt(c1))); return dispatch(self, ip + 1, code); } @@ -1949,7 +1949,7 @@ pub const VirtualMachine = struct { fn @"f64.convert_i64_u"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(u64); - self.pushOperandNoCheck(f64, @intToFloat(f64, c1)); + self.pushOperandNoCheck(f64, @as(f64, @floatFromInt(c1))); return dispatch(self, ip + 1, code); } @@ -1957,7 +1957,7 @@ pub const VirtualMachine = struct { fn @"f64.promote_f32"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(f32); - self.pushOperandNoCheck(f64, @floatCast(f64, c1)); + self.pushOperandNoCheck(f64, @as(f64, @floatCast(c1))); return dispatch(self, ip + 1, code); } @@ -1965,7 +1965,7 @@ pub const VirtualMachine = struct { fn @"i32.reinterpret_f32"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(f32); - self.pushOperandNoCheck(i32, @bitCast(i32, c1)); + self.pushOperandNoCheck(i32, @as(i32, @bitCast(c1))); return dispatch(self, ip + 1, code); } @@ -1973,7 +1973,7 @@ pub const VirtualMachine = struct { fn @"i64.reinterpret_f64"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(f64); - self.pushOperandNoCheck(i64, @bitCast(i64, c1)); + self.pushOperandNoCheck(i64, @as(i64, @bitCast(c1))); return dispatch(self, ip + 1, code); } @@ -1981,7 +1981,7 @@ pub const VirtualMachine = struct { fn @"f32.reinterpret_i32"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i32); - self.pushOperandNoCheck(f32, @bitCast(f32, c1)); + self.pushOperandNoCheck(f32, @as(f32, @bitCast(c1))); return dispatch(self, ip + 1, code); } @@ -1989,7 +1989,7 @@ pub const VirtualMachine = struct { fn @"f64.reinterpret_i64"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i64); - self.pushOperandNoCheck(f64, @bitCast(f64, c1)); + self.pushOperandNoCheck(f64, @as(f64, @bitCast(c1))); return dispatch(self, ip + 1, code); } @@ -1997,7 +1997,7 @@ pub const VirtualMachine = struct { fn @"i32.extend8_s"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i32); - self.pushOperandNoCheck(i32, @truncate(i8, c1)); + self.pushOperandNoCheck(i32, @as(i8, @truncate(c1))); return dispatch(self, ip + 1, code); } @@ -2005,7 +2005,7 @@ pub const VirtualMachine = struct { fn @"i32.extend16_s"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i32); - self.pushOperandNoCheck(i32, @truncate(i16, c1)); + self.pushOperandNoCheck(i32, @as(i16, @truncate(c1))); return dispatch(self, ip + 1, code); } @@ -2013,7 +2013,7 @@ pub const VirtualMachine = struct { fn @"i64.extend8_s"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i64); - self.pushOperandNoCheck(i64, @truncate(i8, c1)); + self.pushOperandNoCheck(i64, @as(i8, @truncate(c1))); return dispatch(self, ip + 1, code); } @@ -2021,7 +2021,7 @@ pub const VirtualMachine = struct { fn @"i64.extend16_s"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i64); - self.pushOperandNoCheck(i64, @truncate(i16, c1)); + self.pushOperandNoCheck(i64, @as(i16, @truncate(c1))); return dispatch(self, ip + 1, code); } @@ -2029,7 +2029,7 @@ pub const VirtualMachine = struct { fn @"i64.extend32_s"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { const c1 = self.popOperand(i64); - self.pushOperandNoCheck(i64, @truncate(i32, c1)); + self.pushOperandNoCheck(i64, @as(i32, @truncate(c1))); return dispatch(self, ip + 1, code); } @@ -2074,7 +2074,7 @@ pub const VirtualMachine = struct { inline fn miscDispatch(self: *VirtualMachine, next_ip: usize, code: []Rr) WasmError!void { const next_instr = code[next_ip].misc; - return try @call(.{ .modifier = .always_tail }, misc_lookup[@enumToInt(next_instr)], .{ self, next_ip, code }); + return try @call(.always_tail, misc_lookup[@intFromEnum(next_instr)], .{ self, next_ip, code }); } fn @"i32.trunc_sat_f32_s"(self: *VirtualMachine, ip: usize, code: []Rr) WasmError!void { @@ -2086,16 +2086,16 @@ pub const VirtualMachine = struct { return dispatch(self, ip + 1, code); } - if (trunc >= @intToFloat(f32, math.maxInt(i32))) { - self.pushOperandNoCheck(i32, @bitCast(i32, @as(u32, 0x7fffffff))); + if (trunc >= @as(f32, @floatFromInt(math.maxInt(i32)))) { + self.pushOperandNoCheck(i32, @as(i32, @bitCast(@as(u32, 0x7fffffff)))); return dispatch(self, ip + 1, code); } - if (trunc < @intToFloat(f32, math.minInt(i32))) { - self.pushOperandNoCheck(i32, @bitCast(i32, @as(u32, 0x80000000))); + if (trunc < @as(f32, @floatFromInt(math.minInt(i32)))) { + self.pushOperandNoCheck(i32, @as(i32, @bitCast(@as(u32, 0x80000000)))); return dispatch(self, ip + 1, code); } - self.pushOperandNoCheck(i32, @floatToInt(i32, trunc)); + self.pushOperandNoCheck(i32, @as(i32, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -2108,16 +2108,16 @@ pub const VirtualMachine = struct { return dispatch(self, ip + 1, code); } - if (trunc >= @intToFloat(f32, math.maxInt(u32))) { - self.pushOperandNoCheck(u32, @bitCast(u32, @as(u32, 0xffffffff))); + if (trunc >= @as(f32, @floatFromInt(math.maxInt(u32)))) { + self.pushOperandNoCheck(u32, @as(u32, @bitCast(@as(u32, 0xffffffff)))); return dispatch(self, ip + 1, code); } - if (trunc < @intToFloat(f32, math.minInt(u32))) { - self.pushOperandNoCheck(u32, @bitCast(u32, @as(u32, 0x00000000))); + if (trunc < @as(f32, @floatFromInt(math.minInt(u32)))) { + self.pushOperandNoCheck(u32, @as(u32, @bitCast(@as(u32, 0x00000000)))); return dispatch(self, ip + 1, code); } - self.pushOperandNoCheck(u32, @floatToInt(u32, trunc)); + self.pushOperandNoCheck(u32, @as(u32, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -2130,16 +2130,16 @@ pub const VirtualMachine = struct { return dispatch(self, ip + 1, code); } - if (trunc >= @intToFloat(f64, math.maxInt(i32))) { - self.pushOperandNoCheck(i32, @bitCast(i32, @as(u32, 0x7fffffff))); + if (trunc >= @as(f64, @floatFromInt(math.maxInt(i32)))) { + self.pushOperandNoCheck(i32, @as(i32, @bitCast(@as(u32, 0x7fffffff)))); return dispatch(self, ip + 1, code); } - if (trunc < @intToFloat(f64, math.minInt(i32))) { - self.pushOperandNoCheck(i32, @bitCast(i32, @as(u32, 0x80000000))); + if (trunc < @as(f64, @floatFromInt(math.minInt(i32)))) { + self.pushOperandNoCheck(i32, @as(i32, @bitCast(@as(u32, 0x80000000)))); return dispatch(self, ip + 1, code); } - self.pushOperandNoCheck(i32, @floatToInt(i32, trunc)); + self.pushOperandNoCheck(i32, @as(i32, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -2152,16 +2152,16 @@ pub const VirtualMachine = struct { return dispatch(self, ip + 1, code); } - if (trunc >= @intToFloat(f64, math.maxInt(u32))) { - self.pushOperandNoCheck(u32, @bitCast(u32, @as(u32, 0xffffffff))); + if (trunc >= @as(f64, @floatFromInt(math.maxInt(u32)))) { + self.pushOperandNoCheck(u32, @as(u32, @bitCast(@as(u32, 0xffffffff)))); return dispatch(self, ip + 1, code); } - if (trunc < @intToFloat(f64, math.minInt(u32))) { - self.pushOperandNoCheck(u32, @bitCast(u32, @as(u32, 0x00000000))); + if (trunc < @as(f64, @floatFromInt(math.minInt(u32)))) { + self.pushOperandNoCheck(u32, @as(u32, @bitCast(@as(u32, 0x00000000)))); return dispatch(self, ip + 1, code); } - self.pushOperandNoCheck(u32, @floatToInt(u32, trunc)); + self.pushOperandNoCheck(u32, @as(u32, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -2174,16 +2174,16 @@ pub const VirtualMachine = struct { return dispatch(self, ip + 1, code); } - if (trunc >= @intToFloat(f32, math.maxInt(i64))) { - self.pushOperandNoCheck(i64, @bitCast(i64, @as(u64, 0x7fffffffffffffff))); + if (trunc >= @as(f32, @floatFromInt(math.maxInt(i64)))) { + self.pushOperandNoCheck(i64, @as(i64, @bitCast(@as(u64, 0x7fffffffffffffff)))); return dispatch(self, ip + 1, code); } - if (trunc < @intToFloat(f32, math.minInt(i64))) { - self.pushOperandNoCheck(i64, @bitCast(i64, @as(u64, 0x8000000000000000))); + if (trunc < @as(f32, @floatFromInt(math.minInt(i64)))) { + self.pushOperandNoCheck(i64, @as(i64, @bitCast(@as(u64, 0x8000000000000000)))); return dispatch(self, ip + 1, code); } - self.pushOperandNoCheck(i64, @floatToInt(i64, trunc)); + self.pushOperandNoCheck(i64, @as(i64, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -2196,16 +2196,16 @@ pub const VirtualMachine = struct { return dispatch(self, ip + 1, code); } - if (trunc >= @intToFloat(f32, math.maxInt(u64))) { - self.pushOperandNoCheck(u64, @bitCast(u64, @as(u64, 0xffffffffffffffff))); + if (trunc >= @as(f32, @floatFromInt(math.maxInt(u64)))) { + self.pushOperandNoCheck(u64, @as(u64, @bitCast(@as(u64, 0xffffffffffffffff)))); return dispatch(self, ip + 1, code); } - if (trunc < @intToFloat(f32, math.minInt(u64))) { - self.pushOperandNoCheck(u64, @bitCast(u64, @as(u64, 0x0000000000000000))); + if (trunc < @as(f32, @floatFromInt(math.minInt(u64)))) { + self.pushOperandNoCheck(u64, @as(u64, @bitCast(@as(u64, 0x0000000000000000)))); return dispatch(self, ip + 1, code); } - self.pushOperandNoCheck(u64, @floatToInt(u64, trunc)); + self.pushOperandNoCheck(u64, @as(u64, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -2218,16 +2218,16 @@ pub const VirtualMachine = struct { return dispatch(self, ip + 1, code); } - if (trunc >= @intToFloat(f64, math.maxInt(i64))) { - self.pushOperandNoCheck(i64, @bitCast(i64, @as(u64, 0x7fffffffffffffff))); + if (trunc >= @as(f64, @floatFromInt(math.maxInt(i64)))) { + self.pushOperandNoCheck(i64, @as(i64, @bitCast(@as(u64, 0x7fffffffffffffff)))); return dispatch(self, ip + 1, code); } - if (trunc < @intToFloat(f64, math.minInt(i64))) { - self.pushOperandNoCheck(i64, @bitCast(i64, @as(u64, 0x8000000000000000))); + if (trunc < @as(f64, @floatFromInt(math.minInt(i64)))) { + self.pushOperandNoCheck(i64, @as(i64, @bitCast(@as(u64, 0x8000000000000000)))); return dispatch(self, ip + 1, code); } - self.pushOperandNoCheck(i64, @floatToInt(i64, trunc)); + self.pushOperandNoCheck(i64, @as(i64, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -2240,16 +2240,16 @@ pub const VirtualMachine = struct { return dispatch(self, ip + 1, code); } - if (trunc >= @intToFloat(f64, math.maxInt(u64))) { - self.pushOperandNoCheck(u64, @bitCast(u64, @as(u64, 0xffffffffffffffff))); + if (trunc >= @as(f64, @floatFromInt(math.maxInt(u64)))) { + self.pushOperandNoCheck(u64, @as(u64, @bitCast(@as(u64, 0xffffffffffffffff)))); return dispatch(self, ip + 1, code); } - if (trunc < @intToFloat(f64, math.minInt(u64))) { - self.pushOperandNoCheck(u64, @bitCast(u64, @as(u64, 0x0000000000000000))); + if (trunc < @as(f64, @floatFromInt(math.minInt(u64)))) { + self.pushOperandNoCheck(u64, @as(u64, @bitCast(@as(u64, 0x0000000000000000)))); return dispatch(self, ip + 1, code); } - self.pushOperandNoCheck(u64, @floatToInt(u64, trunc)); + self.pushOperandNoCheck(u64, @as(u64, @intFromFloat(trunc))); return dispatch(self, ip + 1, code); } @@ -2327,7 +2327,7 @@ pub const VirtualMachine = struct { return dispatch(self, ip + 1, code); } - memory.uncheckedFill(dest, n, @truncate(u8, value)); + memory.uncheckedFill(dest, n, @as(u8, @truncate(value))); return dispatch(self, ip + 1, code); } @@ -2432,7 +2432,7 @@ pub const VirtualMachine = struct { const table = try self.inst.getTable(tableidx); - self.pushOperandNoCheck(u32, @intCast(u32, table.size())); + self.pushOperandNoCheck(u32, @as(u32, @intCast(table.size()))); return dispatch(self, ip + 1, code); } @@ -2482,10 +2482,10 @@ pub const VirtualMachine = struct { self.op_ptr += 1; self.op_stack[self.op_ptr - 1] = switch (T) { - i32 => @as(u64, @bitCast(u32, value)), - i64 => @bitCast(u64, value), - f32 => @as(u64, @bitCast(u32, value)), - f64 => @bitCast(u64, value), + i32 => @as(u32, @bitCast(value)), + i64 => @as(u64, @bitCast(value)), + f32 => @as(u32, @bitCast(value)), + f64 => @as(u64, @bitCast(value)), u32 => @as(u64, value), u64 => value, else => |t| @compileError("Unsupported operand type: " ++ @typeName(t)), @@ -2500,10 +2500,10 @@ pub const VirtualMachine = struct { self.op_ptr += 1; self.op_stack[self.op_ptr - 1] = switch (T) { - i32 => @as(u64, @bitCast(u32, value)), - i64 => @bitCast(u64, value), - f32 => @as(u64, @bitCast(u32, value)), - f64 => @bitCast(u64, value), + i32 => @as(u32, @bitCast(value)), + i64 => @as(u64, @bitCast(value)), + f32 => @as(u32, @bitCast(value)), + f64 => @as(u64, @bitCast(value)), u32 => @as(u64, value), u64 => value, else => |t| @compileError("Unsupported operand type: " ++ @typeName(t)), @@ -2515,11 +2515,11 @@ pub const VirtualMachine = struct { const value = self.op_stack[self.op_ptr - 1]; return switch (T) { - i32 => @bitCast(i32, @truncate(u32, value)), - i64 => @bitCast(i64, value), - f32 => @bitCast(f32, @truncate(u32, value)), - f64 => @bitCast(f64, value), - u32 => @truncate(u32, value), + i32 => @as(i32, @bitCast(@as(u32, @truncate(value)))), + i64 => @as(i64, @bitCast(value)), + f32 => @as(f32, @bitCast(@as(u32, @truncate(value)))), + f64 => @as(f64, @bitCast(value)), + u32 => @as(u32, @truncate(value)), u64 => value, else => |t| @compileError("Unsupported operand type: " ++ @typeName(t)), }; @@ -2684,4 +2684,3 @@ test "operand push / pop test" { // try testing.expectEqual(@as(i32, -1), i.popOperand(i32)); // } - diff --git a/src/module.zig b/src/module.zig index fae74ec2..d41584f7 100644 --- a/src/module.zig +++ b/src/module.zig @@ -200,11 +200,11 @@ pub const Module = struct { var results = self.module[results_start..results_end]; var params_valtype: []const ValType = undefined; - params_valtype.ptr = @ptrCast([*]const ValType, params.ptr); + params_valtype.ptr = @ptrCast(params.ptr); params_valtype.len = params.len; var results_valtype: []const ValType = undefined; - results_valtype.ptr = @ptrCast([*]const ValType, results.ptr); + results_valtype.ptr = @ptrCast(results.ptr); results_valtype.len = results.len; try self.types.list.append(FuncType{ @@ -233,7 +233,7 @@ pub const Module = struct { const tag = try self.readEnum(Tag); if (i > math.maxInt(u32)) return error.ExpectedU32Index; - const import_index = @truncate(u32, i); + const import_index: u32 = @truncate(i); _ = switch (tag) { .Func => try self.decodeFunction(import_index), .Table => try self.decodeTable(import_index), @@ -1061,7 +1061,7 @@ test "module loading (simple add function)" { var in = [2]u64{ 22, 23 }; var out = [1]u64{0}; try instance.invoke("add", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 45), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 45), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); } test "module loading (fib)" { @@ -1085,31 +1085,31 @@ test "module loading (fib)" { var in = [1]u64{0}; var out = [1]u64{0}; try instance.invoke("fib", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 0), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 0), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); in[0] = 1; try instance.invoke("fib", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 1), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 1), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); in[0] = 2; try instance.invoke("fib", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 1), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 1), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); in[0] = 3; try instance.invoke("fib", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 2), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 2), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); in[0] = 4; try instance.invoke("fib", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 3), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 3), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); in[0] = 5; try instance.invoke("fib", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 5), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 5), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); in[0] = 6; try instance.invoke("fib", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 8), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 8), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); } test "module loading (fact)" { @@ -1133,21 +1133,21 @@ test "module loading (fact)" { var in = [1]u64{1}; var out = [1]u64{0}; try instance.invoke("fact", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 1), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 1), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); in[0] = 2; try instance.invoke("fact", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 2), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 2), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); in[0] = 3; try instance.invoke("fact", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 6), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 6), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); in[0] = 4; try instance.invoke("fact", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 24), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 24), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); in[0] = 12; try instance.invoke("fact", in[0..], out[0..], .{}); - try testing.expectEqual(@as(i32, 479001600), @bitCast(i32, @truncate(u32, out[0]))); + try testing.expectEqual(@as(i32, 479001600), @as(i32, @bitCast(@as(u32, @truncate(out[0]))))); } diff --git a/src/module/parser.zig b/src/module/parser.zig index bd086b69..0c8f8d24 100644 --- a/src/module/parser.zig +++ b/src/module/parser.zig @@ -97,7 +97,7 @@ pub const Parser = struct { .@"ref.null", .@"ref.func", .end, - => |_| {}, + => {}, else => return error.ValidatorConstantExpressionRequired, } try self.module.parsed_code.append(instr); @@ -174,7 +174,7 @@ pub const Parser = struct { var block_returns: u16 = if (block_type == -0x40) 0 else 1; if (block_type >= 0) { - const funcidx = @intCast(u32, block_type); + const funcidx: u32 = @intCast(block_type); const functype = try self.module.types.lookup(funcidx); block_params = math.cast(u16, functype.params.len) orelse return error.FailedCast; block_returns = math.cast(u16, functype.results.len) orelse return error.FailedCast; @@ -212,7 +212,7 @@ pub const Parser = struct { var block_params: u16 = 0; var block_returns: u16 = if (block_type == -0x40) 0 else 1; if (block_type >= 0) { - const funcidx = @intCast(u32, block_type); + const funcidx: u32 = @intCast(block_type); const functype = try self.module.types.lookup(funcidx); block_params = math.cast(u16, functype.params.len) orelse return error.FailedCast; block_returns = math.cast(u16, functype.results.len) orelse return error.FailedCast; @@ -255,7 +255,7 @@ pub const Parser = struct { var block_params: u16 = 0; var block_returns: u16 = if (block_type == -0x40) 0 else 1; if (block_type >= 0) { - const funcidx = @intCast(u32, block_type); + const funcidx: u32 = @intCast(block_type); const functype = try self.module.types.lookup(funcidx); block_params = math.cast(u16, functype.params.len) orelse return error.FailedCast; block_returns = math.cast(u16, functype.results.len) orelse return error.FailedCast; @@ -554,11 +554,11 @@ pub const Parser = struct { rr = Rr{ .@"i64.const" = i64_const }; }, .@"f32.const" => { - const float_const = @bitCast(f32, try self.readU32()); + const float_const: f32 = @bitCast(try self.readU32()); rr = Rr{ .@"f32.const" = float_const }; }, .@"f64.const" => { - const float_const = @bitCast(f64, try self.readU64()); + const float_const: f64 = @bitCast(try self.readU64()); rr = Rr{ .@"f64.const" = float_const }; }, .@"i32.load" => { diff --git a/src/module/validator.zig b/src/module/validator.zig index 9c64d357..c00e39d2 100644 --- a/src/module/validator.zig +++ b/src/module/validator.zig @@ -84,11 +84,11 @@ pub const Validator = struct { if (!(arity <= 64)) return error.TODOAllocation; var temp = [_]Type{.{ .Known = .I32 }} ** 64; // TODO: allocate some memory for this - for (labelTypes(frame_n)) |_, i| { + for (labelTypes(frame_n), 0..) |_, i| { temp[i] = try v.popOperandExpecting(Type{ .Known = labelTypes(frame_n)[arity - i - 1] }); } - for (labelTypes(frame_n)) |_, i| { + for (labelTypes(frame_n), 0..) |_, i| { try v.pushOperand(temp[arity - 1 - i]); } } @@ -581,7 +581,7 @@ pub const Validator = struct { fn popOperands(v: *Validator, operands: []const ValType) !void { const len = operands.len; - for (operands) |_, i| { + for (operands, 0..) |_, i| { _ = try v.popOperandExpecting(Type{ .Known = operands[len - i - 1] }); } } diff --git a/src/store/function.zig b/src/store/function.zig index 6e20ae98..c1c793cd 100644 --- a/src/store/function.zig +++ b/src/store/function.zig @@ -24,11 +24,11 @@ pub const Function = struct { if (self.params.len != b.params.len) return error.MismatchedSignatures; if (self.results.len != b.results.len) return error.MismatchedSignatures; - for (self.params) |p_a, i| { + for (self.params, 0..) |p_a, i| { if (p_a != b.params[i]) return error.MismatchedSignatures; } - for (self.results) |r_a, i| { + for (self.results, 0..) |r_a, i| { if (r_a != b.results[i]) return error.MismatchedSignatures; } } diff --git a/src/store/memory.zig b/src/store/memory.zig index 6a2bf1c6..69c533b7 100644 --- a/src/store/memory.zig +++ b/src/store/memory.zig @@ -1,6 +1,5 @@ const std = @import("std"); const mem = std.mem; -const math = std.math; const ArrayList = std.ArrayList; pub const MAX_PAGES = 64 * 1024; @@ -25,23 +24,23 @@ pub const Memory = struct { pub fn size(self: *Memory) u32 { std.debug.assert(self.data.items.len % PAGE_SIZE == 0); - return @truncate(u32, self.data.items.len / PAGE_SIZE); + return @truncate(self.data.items.len / PAGE_SIZE); } pub fn sizeBytes(self: *Memory) u33 { // FIXME: add assertion that len fits in u33 - return @truncate(u33, self.data.items.len); + return @truncate(self.data.items.len); } pub fn grow(self: *Memory, num_pages: u32) !usize { - if (self.size() + num_pages > math.min(self.max orelse MAX_PAGES, MAX_PAGES)) return error.OutOfBoundsMemoryAccess; + if (self.size() + num_pages > @min(self.max orelse MAX_PAGES, MAX_PAGES)) return error.OutOfBoundsMemoryAccess; const old_size_in_bytes = self.data.items.len; const old_size_in_pages = self.size(); _ = try self.data.resize(self.data.items.len + PAGE_SIZE * num_pages); // Zero memory. FIXME: I don't think this is required (maybe do this only in debug build) - mem.set(u8, self.data.items[old_size_in_bytes .. old_size_in_bytes + PAGE_SIZE * num_pages], 0); + @memset(self.data.items[old_size_in_bytes .. old_size_in_bytes + PAGE_SIZE * num_pages], 0); return old_size_in_pages; } @@ -53,7 +52,7 @@ pub const Memory = struct { } pub fn uncheckedFill(self: *Memory, dst_address: u32, n: u32, value: u8) void { - mem.set(u8, self.data.items[dst_address .. dst_address + n], value); + @memset(self.data.items[dst_address .. dst_address + n], value); } pub fn uncheckedCopy(self: *Memory, dst_address: u32, data: []const u8) void { @@ -83,14 +82,14 @@ pub const Memory = struct { i16, i32, i64, - => return mem.readInt(T, @ptrCast(*const [@sizeOf(T)]u8, &self.data.items[effective_address]), .Little), + => return mem.readInt(T, @as(*const [@sizeOf(T)]u8, @ptrCast(&self.data.items[effective_address])), .Little), f32 => { - const x = mem.readInt(u32, @ptrCast(*const [@sizeOf(T)]u8, &self.data.items[effective_address]), .Little); - return @bitCast(f32, x); + const x = mem.readInt(u32, @as(*const [@sizeOf(T)]u8, @ptrCast(&self.data.items[effective_address])), .Little); + return @bitCast(x); }, f64 => { - const x = mem.readInt(u64, @ptrCast(*const [@sizeOf(T)]u8, &self.data.items[effective_address]), .Little); - return @bitCast(f64, x); + const x = mem.readInt(u64, @as(*const [@sizeOf(T)]u8, @ptrCast(&self.data.items[effective_address])), .Little); + return @bitCast(x); }, else => @compileError("Memory.read unsupported type (not int/float): " ++ @typeName(T)), } @@ -109,14 +108,14 @@ pub const Memory = struct { i16, i32, i64, - => std.mem.writeInt(T, @ptrCast(*[@sizeOf(T)]u8, &self.data.items[effective_address]), value, .Little), + => std.mem.writeInt(T, @as(*[@sizeOf(T)]u8, @ptrCast(&self.data.items[effective_address])), value, .Little), f32 => { - const x = @bitCast(u32, value); - std.mem.writeInt(u32, @ptrCast(*[@sizeOf(u32)]u8, &self.data.items[effective_address]), x, .Little); + const x: u32 = @bitCast(value); + std.mem.writeInt(u32, @as(*[@sizeOf(u32)]u8, @ptrCast(&self.data.items[effective_address])), x, .Little); }, f64 => { - const x = @bitCast(u64, value); - std.mem.writeInt(u64, @ptrCast(*[@sizeOf(u64)]u8, &self.data.items[effective_address]), x, .Little); + const x: u64 = @bitCast(value); + std.mem.writeInt(u64, @as(*[@sizeOf(u64)]u8, @ptrCast(&self.data.items[effective_address])), x, .Little); }, else => @compileError("Memory.read unsupported type (not int/float): " ++ @typeName(T)), } diff --git a/test/fuzzer/build.zig b/test/fuzzer/build.zig index e3b74321..8e3e6b66 100644 --- a/test/fuzzer/build.zig +++ b/test/fuzzer/build.zig @@ -1,23 +1,21 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - // Standard target options allows the person running `zig build` to choose - // what target to build for. Here we do not override the defaults, which - // means any target is allowed, and the default is native. Other options - // for restricting supported target set are available. const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); - // Standard release options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); + const exe = b.addExecutable(.{ + .name = "fuzzer", + .root_source_file = .{ .path = "src/fuzzer.zig" }, + .target = target, + .optimize = optimize, + }); + exe.addAnonymousModule("zware", .{ + .source_file = .{ .path = "../../src/main.zig" }, + }); + b.installArtifact(exe); - const exe = b.addExecutable("fuzzer", "src/fuzzer.zig"); - exe.setTarget(target); - exe.setBuildMode(mode); - exe.addPackagePath("zware", "../../src/main.zig"); - exe.install(); - - const run_cmd = exe.run(); + const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { run_cmd.addArgs(args); diff --git a/test/fuzzer/src/fuzzer.zig b/test/fuzzer/src/fuzzer.zig index 1696b13b..ae774a6e 100644 --- a/test/fuzzer/src/fuzzer.zig +++ b/test/fuzzer/src/fuzzer.zig @@ -39,7 +39,7 @@ pub fn main() !void { var file_count: usize = 0; while (try it.next()) |entry| { - if (entry.kind == .File) file_count += 1; + if (entry.kind == .file) file_count += 1; if (mem.endsWith(u8, entry.name, ".wasm")) { const s = try name_alloc.alloc(u8, entry.name.len); mem.copy(u8, s, entry.name); @@ -96,11 +96,11 @@ pub fn main() !void { } } -pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) noreturn { +pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn { var out_dir = std.fs.cwd().openDir(fuzzed_dir, .{}) catch unreachable; defer out_dir.close(); std.log.info("Fuzzer found bug: {s}", .{fuzzed_name}); out_dir.writeFile(fuzzed_name, program) catch unreachable; - std.builtin.default_panic(msg, error_return_trace); + std.builtin.default_panic(msg, error_return_trace, ret_addr); } diff --git a/test/interface/build.zig b/test/interface/build.zig index 11f50c64..c3a5b4c8 100644 --- a/test/interface/build.zig +++ b/test/interface/build.zig @@ -1,23 +1,21 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - // Standard target options allows the person running `zig build` to choose - // what target to build for. Here we do not override the defaults, which - // means any target is allowed, and the default is native. Other options - // for restricting supported target set are available. const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); - // Standard release options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); + const exe = b.addExecutable(.{ + .name = "interface", + .root_source_file = .{ .path = "src/interface.zig" }, + .target = target, + .optimize = optimize, + }); + exe.addAnonymousModule("zware", .{ + .source_file = .{ .path = "../../src/main.zig" }, + }); + b.installArtifact(exe); - const exe = b.addExecutable("interface", "src/interface.zig"); - exe.setTarget(target); - exe.setBuildMode(mode); - exe.addPackagePath("zware", "../../src/main.zig"); - exe.install(); - - const run_cmd = exe.run(); + const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { run_cmd.addArgs(args); diff --git a/test/interface/src/interface.zig b/test/interface/src/interface.zig index 5d83c19f..f33eeff3 100644 --- a/test/interface/src/interface.zig +++ b/test/interface/src/interface.zig @@ -27,12 +27,12 @@ pub fn main() !void { try module.decode(); std.log.info("Imports:", .{}); - for (module.imports.list.items) |import, i| { + for (module.imports.list.items, 0..) |import, i| { std.log.info("{}: import = {s}, tag = {}", .{ i, import.name, import.desc_tag }); } std.log.info("Exports:", .{}); - for (module.exports.list.items) |exprt, i| { + for (module.exports.list.items, 0..) |exprt, i| { std.log.info("{}: export = {s}, tag = {}", .{ i, exprt.name, exprt.tag }); } } diff --git a/test/parsecheck/build.zig b/test/parsecheck/build.zig index c0b38229..fa711634 100644 --- a/test/parsecheck/build.zig +++ b/test/parsecheck/build.zig @@ -1,23 +1,21 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - // Standard target options allows the person running `zig build` to choose - // what target to build for. Here we do not override the defaults, which - // means any target is allowed, and the default is native. Other options - // for restricting supported target set are available. const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); - // Standard release options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); + const exe = b.addExecutable(.{ + .name = "parsecheck", + .root_source_file = .{ .path = "src/parsecheck.zig" }, + .target = target, + .optimize = optimize, + }); + exe.addAnonymousModule("zware", .{ + .source_file = .{ .path = "../../src/main.zig" }, + }); + b.installArtifact(exe); - const exe = b.addExecutable("parsecheck", "src/parsecheck.zig"); - exe.setTarget(target); - exe.setBuildMode(mode); - exe.addPackagePath("zware", "../../src/main.zig"); - exe.install(); - - const run_cmd = exe.run(); + const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { run_cmd.addArgs(args); diff --git a/test/parsecheck/src/parsecheck.zig b/test/parsecheck/src/parsecheck.zig index b3c8fa5d..09cc0192 100644 --- a/test/parsecheck/src/parsecheck.zig +++ b/test/parsecheck/src/parsecheck.zig @@ -29,7 +29,7 @@ pub fn main() !void { var file_count: usize = 0; while (try it.next()) |entry| { - if (entry.kind == .File) file_count += 1; + if (entry.kind == .file) file_count += 1; if (mem.endsWith(u8, entry.name, ".wasm")) { std.log.info("{s}", .{entry.name}); var arena = ArenaAllocator.init(gpa.allocator()); diff --git a/test/run-generated.sh b/test/run-generated.sh index 09e24043..8e2fc622 100644 --- a/test/run-generated.sh +++ b/test/run-generated.sh @@ -2,7 +2,7 @@ set -e SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" -BIN_DIR=$SCRIPT_DIR/../bin +BIN_DIR=$SCRIPT_DIR/testrunner/bin GENERATED_DIR=$SCRIPT_DIR/testsuite-generated pushd $GENERATED_DIR diff --git a/test/testrunner/build.zig b/test/testrunner/build.zig index 9337c575..8909ef24 100644 --- a/test/testrunner/build.zig +++ b/test/testrunner/build.zig @@ -1,23 +1,21 @@ const Builder = @import("std").build.Builder; pub fn build(b: *Builder) void { - // Standard target options allows the person running `zig build` to choose - // what target to build for. Here we do not override the defaults, which - // means any target is allowed, and the default is native. Other options - // for restricting supported target set are available. const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); - // Standard release options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - const mode = b.standardReleaseOptions(); + const exe = b.addExecutable(.{ + .name = "testrunner", + .root_source_file = .{ .path = "src/testrunner.zig" }, + .target = target, + .optimize = optimize, + }); + exe.addAnonymousModule("zware", .{ + .source_file = .{ .path = "../../src/main.zig" }, + }); + b.installArtifact(exe); - const exe = b.addExecutable("testrunner", "src/testrunner.zig"); - exe.setTarget(target); - exe.setBuildMode(mode); - exe.addPackagePath("zware", "../../src/main.zig"); - exe.install(); - - const run_cmd = exe.run(); + const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { run_cmd.addArgs(args); diff --git a/test/testrunner/src/testrunner.zig b/test/testrunner/src/testrunner.zig index 4eda09ea..9a91339f 100644 --- a/test/testrunner/src/testrunner.zig +++ b/test/testrunner/src/testrunner.zig @@ -87,15 +87,8 @@ pub fn main() anyerror!void { // 2. Parse json and find .wasm file const json_string = try fs.cwd().readFileAlloc(alloc, filename, 0xFFFFFFF); - // See https://github.com/ziglang/zig/issues/12624 - comptime { - @setEvalBranchQuota(100000); - _ = json.ParseError([]const Command); - _ = json.ParseError(Wast); - } - - var ts = json.TokenStream.init(json_string); - const r = try json.parse(Wast, &ts, json.ParseOptions{ .allocator = alloc }); + const dynamic_tree = try std.json.parseFromSliceLeaky(std.json.Value, alloc, json_string, .{}); + const r = try std.json.parseFromValueLeaky(Wast, alloc, dynamic_tree, .{}); // 2.a. Find the wasm file var wasm_filename: []const u8 = undefined; @@ -302,7 +295,7 @@ pub fn main() anyerror!void { var out = try alloc.alloc(u64, expected.len); // Initialise input parameters - for (action.invoke.args) |value, i| { + for (action.invoke.args, 0..) |value, i| { if (mem.eql(u8, value.value, "null")) { in[i] = VirtualMachine.REF_NULL; } else { @@ -318,15 +311,15 @@ pub fn main() anyerror!void { return err; }; - for (expected) |result, i| { - const valtype = try valueTypeFromString(result.@"type"); + for (expected, 0..) |result, i| { + const valtype = try valueTypeFromString(result.type); switch (valtype) { .I32, .I64, .F32, .F64 => { if (mem.startsWith(u8, result.value, "nan:")) { - if (valtype == .F32 and math.isNan(@bitCast(f32, @truncate(u32, out[i])))) { + if (valtype == .F32 and math.isNan(@as(f32, @bitCast(@as(u32, @truncate(out[i])))))) { continue; } - if (valtype == .F64 and math.isNan(@bitCast(f64, out[i]))) { + if (valtype == .F64 and math.isNan(@as(f64, @bitCast(out[i])))) { continue; } @@ -380,7 +373,7 @@ pub fn main() anyerror!void { if (mem.eql(u8, exprt.name, field)) { const global = try registered_inst.getGlobal(exprt.index); - for (expected) |result, j| { + for (expected, 0..) |result, j| { if (j > 0) return error.ExpectedOneResult; const result_value = try fmt.parseInt(u64, result.value, 10); @@ -391,11 +384,11 @@ pub fn main() anyerror!void { } } } else { - for (current_instance.module.exports.list.items) |exprt, i| { + for (current_instance.module.exports.list.items, 0..) |exprt, i| { if (mem.eql(u8, exprt.name, field)) { const global = try current_instance.getGlobal(i); - for (expected) |result, j| { + for (expected, 0..) |result, j| { if (j > 0) return error.ExpectedOneResult; const result_value = try fmt.parseInt(u64, result.value, 10); if (global.value != result_value) { @@ -434,7 +427,7 @@ pub fn main() anyerror!void { var out = try alloc.alloc(u64, expected.len); // Initialise input parameters - for (action.invoke.args) |value, i| { + for (action.invoke.args, 0..) |value, i| { if (mem.eql(u8, value.value, "null")) { in[i] = VirtualMachine.REF_NULL; } else { @@ -779,7 +772,7 @@ pub fn main() anyerror!void { var out = try alloc.alloc(u64, expected.len); // Initialise input parameters - for (action.invoke.args) |value, i| { + for (action.invoke.args, 0..) |value, i| { const arg = try fmt.parseInt(u64, value.value, 10); in[i] = arg; } @@ -913,85 +906,162 @@ const Wast = struct { commands: []const Command, }; -const Command = union(enum) { module: struct { - comptime @"type": []const u8 = "module", +const Command = union(enum) { + module: CommandModule, + assert_return: CommandAssertReturn, + assert_trap: CommandAssertTrap, + assert_malformed: CommandAssertMalformed, + assert_invalid: CommandAssertInvalid, + assert_exhaustion: CommandAssertExhaustion, + assert_unlinkable: CommandAssertUnlinkable, + assert_uninstantiable: CommandAssertUninstantiable, + action: CommandAction, + register: CommandRegister, + + pub fn jsonParseFromValue(allocator: mem.Allocator, source: std.json.Value, options: std.json.ParseOptions) !@This() { + if (source != .object) return error.UnexpectedToken; + + const type_value = source.object.get("type") orelse return error.UnexpectedToken; + if (type_value != .string) return error.UnexpectedToken; + + const type_str = type_value.string; + var child_options = options; + + child_options.ignore_unknown_fields = true; + + if (std.mem.eql(u8, type_str, "module")) return .{ .module = try std.json.parseFromValueLeaky(CommandModule, allocator, source, child_options) }; + if (std.mem.eql(u8, type_str, "assert_return")) return .{ .assert_return = try std.json.parseFromValueLeaky(CommandAssertReturn, allocator, source, child_options) }; + if (std.mem.eql(u8, type_str, "assert_trap")) return .{ .assert_trap = try std.json.parseFromValueLeaky(CommandAssertTrap, allocator, source, child_options) }; + if (std.mem.eql(u8, type_str, "assert_malformed")) return .{ .assert_malformed = try std.json.parseFromValueLeaky(CommandAssertMalformed, allocator, source, child_options) }; + if (std.mem.eql(u8, type_str, "assert_invalid")) return .{ .assert_invalid = try std.json.parseFromValueLeaky(CommandAssertInvalid, allocator, source, child_options) }; + if (std.mem.eql(u8, type_str, "assert_exhaustion")) return .{ .assert_exhaustion = try std.json.parseFromValueLeaky(CommandAssertExhaustion, allocator, source, child_options) }; + if (std.mem.eql(u8, type_str, "assert_unlinkable")) return .{ .assert_unlinkable = try std.json.parseFromValueLeaky(CommandAssertUnlinkable, allocator, source, child_options) }; + if (std.mem.eql(u8, type_str, "assert_uninstantiable")) return .{ .assert_uninstantiable = try std.json.parseFromValueLeaky(CommandAssertUninstantiable, allocator, source, child_options) }; + if (std.mem.eql(u8, type_str, "action")) return .{ .action = try std.json.parseFromValueLeaky(CommandAction, allocator, source, child_options) }; + if (std.mem.eql(u8, type_str, "register")) return .{ .register = try std.json.parseFromValueLeaky(CommandRegister, allocator, source, child_options) }; + + return error.UnexpectedToken; + } +}; + +const CommandModule = struct { + // type: "module" line: usize, name: ?[]const u8 = null, filename: []const u8, -}, assert_return: struct { - comptime @"type": []const u8 = "assert_return", +}; + +const CommandAssertReturn = struct { + // type: "assert_return" line: usize, action: Action, expected: []const Value, -}, assert_trap: struct { - comptime @"type": []const u8 = "assert_trap", +}; + +const CommandAssertTrap = struct { + // type: "assert_trap" line: usize, action: Action, text: []const u8, expected: []const ValueTrap, -}, assert_malformed: struct { - comptime @"type": []const u8 = "assert_malformed", +}; + +const CommandAssertMalformed = struct { + // type: "assert_malformed" line: usize, filename: []const u8, text: []const u8, module_type: []const u8, -}, assert_invalid: struct { - comptime @"type": []const u8 = "assert_invalid", +}; + +const CommandAssertInvalid = struct { + // type: "assert_invalid" line: usize, filename: []const u8, text: []const u8, module_type: []const u8, -}, assert_exhaustion: struct { - comptime @"type": []const u8 = "assert_exhaustion", +}; + +const CommandAssertExhaustion = struct { + // type: "assert_exhaustion" line: usize, action: Action, text: []const u8, expected: []const ValueTrap, -}, assert_unlinkable: struct { - comptime @"type": []const u8 = "assert_unlinkable", +}; + +const CommandAssertUnlinkable = struct { + // type: "assert_unlinkable" line: usize, filename: []const u8, text: []const u8, module_type: []const u8, -}, assert_uninstantiable: struct { - comptime @"type": []const u8 = "assert_uninstantiable", +}; + +const CommandAssertUninstantiable = struct { + // type: "assert_uninstantiable" line: usize, filename: []const u8, text: []const u8, module_type: []const u8, -}, action: struct { - comptime @"type": []const u8 = "action", +}; + +const CommandAction = struct { + // type: "action" line: usize, action: Action, expected: []const ValueTrap, -}, register: struct { - comptime @"type": []const u8 = "register", +}; + +const CommandRegister = struct { + // type: "register" line: usize, name: ?[]const u8 = null, as: []const u8, -} }; +}; + const Action = union(enum) { - invoke: struct { - comptime @"type": []const u8 = "invoke", - field: []const u8, - module: ?[]const u8 = null, - args: []const Value, - }, - get: struct { - comptime @"type": []const u8 = "get", - field: []const u8, - module: ?[]const u8 = null, - }, + invoke: ActionInvoke, + get: ActionGet, + + pub fn jsonParseFromValue(allocator: mem.Allocator, source: std.json.Value, options: std.json.ParseOptions) !@This() { + if (source != .object) return error.UnexpectedToken; + + const type_value = source.object.get("type") orelse return error.UnexpectedToken; + if (type_value != .string) return error.UnexpectedToken; + + const type_str = type_value.string; + var child_options = options; + + child_options.ignore_unknown_fields = true; + + if (std.mem.eql(u8, type_str, "invoke")) return .{ .invoke = try std.json.parseFromValueLeaky(ActionInvoke, allocator, source, child_options) }; + if (std.mem.eql(u8, type_str, "get")) return .{ .get = try std.json.parseFromValueLeaky(ActionGet, allocator, source, child_options) }; + + return error.UnexpectedToken; + } +}; + +const ActionInvoke = struct { + // type: "invoke" + field: []const u8, + module: ?[]const u8 = null, + args: []const Value, +}; + +const ActionGet = struct { + // type: "get" + field: []const u8, + module: ?[]const u8 = null, }; -// const Action = ; const Value = struct { - @"type": []const u8, + type: []const u8, value: []const u8, }; const ValueTrap = struct { - @"type": []const u8, + type: []const u8, };