From b8ec53f708fe0acf3e9d7c01db2eba84324e6d65 Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Mon, 8 Jul 2024 17:42:03 +0200 Subject: [PATCH 1/4] Adapt to js_exec changes in zig-js-runtime Signed-off-by: Francis Bouvier --- src/browser/browser.zig | 76 +++++++++++++++++++++++------------------ src/main.zig | 18 ++++++---- src/main_shell.zig | 2 +- src/main_wpt.zig | 5 ++- src/run_tests.zig | 2 +- src/wpt/run.zig | 52 ++++++++-------------------- vendor/zig-js-runtime | 2 +- 7 files changed, 74 insertions(+), 83 deletions(-) diff --git a/src/browser/browser.zig b/src/browser/browser.zig index c437b53e..9d530eac 100644 --- a/src/browser/browser.zig +++ b/src/browser/browser.zig @@ -198,21 +198,21 @@ pub const Page = struct { } pub fn wait(self: *Page) !void { - const alloc = self.arena.allocator(); - var res = try self.session.env.waitTryCatch(alloc); - defer res.deinit(alloc); - if (res.success) { - log.debug("wait: {s}", .{res.result}); - } else { - if (builtin.mode == .Debug and res.stack != null) { - log.info("wait: {s}", .{res.stack.?}); - } else { - log.info("wait: {s}", .{res.result}); + // try catch + var try_catch: jsruntime.TryCatch = undefined; + try_catch.init(self.session.env); + defer try_catch.deinit(); + + self.session.env.wait() catch { + const alloc = self.arena.allocator(); + if (try try_catch.err(alloc, self.session.env)) |msg| { + defer alloc.free(msg); + std.log.info("wait error: {s}", .{msg}); + return; } - } - - return; + }; + log.debug("wait: OK", .{}); } // spec reference: https://html.spec.whatwg.org/#document-lifecycle @@ -322,7 +322,7 @@ pub const Page = struct { // start JS env // TODO load the js env concurrently with the HTML parsing. log.debug("start js env", .{}); - try self.session.env.start(alloc); + try self.session.env.start(); // replace the user context document with the new one. try self.session.env.setUserContext(.{ @@ -473,22 +473,26 @@ pub const Page = struct { return; } + var try_catch: jsruntime.TryCatch = undefined; + try_catch.init(self.session.env); + defer try_catch.deinit(); + const opt_text = try parser.nodeTextContent(parser.elementToNode(e)); if (opt_text) |text| { // TODO handle charset attribute - var res = try self.session.env.execTryCatch(alloc, text, ""); - defer res.deinit(alloc); - - if (res.success) { - log.debug("eval inline: {s}", .{res.result}); - } else { - if (builtin.mode == .Debug and res.stack != null) { - log.info("eval inline: {s}", .{res.stack.?}); - } else { - log.info("eval inline: {s}", .{res.result}); + const res = self.session.env.exec(text, "") catch { + if (try try_catch.err(alloc, self.session.env)) |msg| { + defer alloc.free(msg); + log.info("eval inline {s}: {s}", .{ text, msg }); } - } + return; + }; + if (builtin.mode == .Debug) { + const msg = try res.toString(alloc, self.session.env); + defer alloc.free(msg); + log.debug("eval inline {s}", .{msg}); + } return; } @@ -530,18 +534,22 @@ pub const Page = struct { // check no body if (body.len == 0) return FetchError.NoBody; - var res = try self.session.env.execTryCatch(alloc, body, src); - defer res.deinit(alloc); + var try_catch: jsruntime.TryCatch = undefined; + try_catch.init(self.session.env); + defer try_catch.deinit(); - if (res.success) { - log.debug("eval remote {s}: {s}", .{ src, res.result }); - } else { - if (builtin.mode == .Debug and res.stack != null) { - log.info("eval remote {s}: {s}", .{ src, res.stack.? }); - } else { - log.info("eval remote {s}: {s}", .{ src, res.result }); + const res = self.session.env.exec(body, src) catch { + if (try try_catch.err(alloc, self.session.env)) |msg| { + defer alloc.free(msg); + log.info("eval remote {s}: {s}", .{ src, msg }); } return FetchError.JsErr; + }; + + if (builtin.mode == .Debug) { + const msg = try res.toString(alloc, self.session.env); + defer alloc.free(msg); + log.debug("eval remote {s}: {s}", .{ src, msg }); } } diff --git a/src/main.zig b/src/main.zig index a402dc48..40b513fe 100644 --- a/src/main.zig +++ b/src/main.zig @@ -37,7 +37,7 @@ fn execJS( js_env: *jsruntime.Env, ) anyerror!void { // start JS env - try js_env.start(alloc); + try js_env.start(); defer js_env.stop(); // alias global as self and window @@ -45,6 +45,11 @@ fn execJS( window.replaceDocument(doc); try js_env.bindGlobal(window); + // try catch + var try_catch: jsruntime.TryCatch = undefined; + try_catch.init(js_env.*); + defer try_catch.deinit(); + while (true) { // read cmd @@ -57,11 +62,12 @@ fn execJS( break; } - const res = try js_env.execTryCatch(alloc, cmd, "cdp"); - if (res.success) { - std.debug.print("-> {s}\n", .{res.result}); - } - _ = try conn.stream.write(res.result); + const res = try js_env.exec(cmd, "cdp"); + const res_str = try res.toString(alloc, js_env.*); + defer alloc.free(res_str); + std.debug.print("-> {s}\n", .{res_str}); + + _ = try conn.stream.write(res_str); } } diff --git a/src/main_shell.zig b/src/main_shell.zig index f766bdd7..9e2510d9 100644 --- a/src/main_shell.zig +++ b/src/main_shell.zig @@ -38,7 +38,7 @@ fn execJS( js_env: *jsruntime.Env, ) anyerror!void { // start JS env - try js_env.start(alloc); + try js_env.start(); defer js_env.stop(); var cli = Client{ .allocator = alloc, .loop = js_env.nat_ctx.loop }; diff --git a/src/main_wpt.zig b/src/main_wpt.zig index 24e4b0fd..aae1984c 100644 --- a/src/main_wpt.zig +++ b/src/main_wpt.zig @@ -141,7 +141,7 @@ pub fn main() !void { var arena = std.heap.ArenaAllocator.init(alloc); defer arena.deinit(); - const res = wpt.run(&arena, wpt_dir, tc, &loader) catch |err| { + const result = wpt.run(&arena, wpt_dir, tc, &loader) catch |err| { const suite = try Suite.init(alloc, tc, false, @errorName(err), null); try results.append(suite); @@ -151,9 +151,8 @@ pub fn main() !void { failures += 1; continue; }; - // no need to call res.deinit() thanks to the arena allocator. - const suite = try Suite.init(alloc, tc, res.success, res.result, res.stack); + const suite = try Suite.init(alloc, tc, true, result, null); try results.append(suite); if (out == .json) { diff --git a/src/run_tests.zig b/src/run_tests.zig index 94d46900..3b235677 100644 --- a/src/run_tests.zig +++ b/src/run_tests.zig @@ -71,7 +71,7 @@ fn testExecFn( defer parser.deinit(); // start JS env - try js_env.start(alloc); + try js_env.start(); defer js_env.stop(); var storageShelf = storage.Shelf.init(alloc); diff --git a/src/wpt/run.zig b/src/wpt/run.zig index 09586db3..50c6eebe 100644 --- a/src/wpt/run.zig +++ b/src/wpt/run.zig @@ -36,7 +36,7 @@ const Client = @import("../async/Client.zig"); // runWPT parses the given HTML file, starts a js env and run the first script // tags containing javascript sources. // It loads first the js libs files. -pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const u8, loader: *FileLoader) !jsruntime.JSResult { +pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const u8, loader: *FileLoader) ![]const u8 { const alloc = arena.allocator(); try parser.init(); defer parser.deinit(); @@ -70,15 +70,15 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const try js_env.load(&js_types); // start JS env - try js_env.start(alloc); + try js_env.start(); defer js_env.stop(); // display console logs defer { - var res = evalJS(js_env, alloc, "console.join('\\n');", "console") catch unreachable; - defer res.deinit(alloc); - if (res.result.len > 0) { - std.debug.print("-- CONSOLE LOG\n{s}\n--\n", .{res.result}); + const res = evalJS(js_env, "console.join('\\n');", "console") catch unreachable; + const res_str = res.toString(alloc, js_env) catch unreachable; + if (res_str.len > 0) { + std.debug.print("-- CONSOLE LOG\n{s}\n--\n", .{res_str}); } } @@ -89,7 +89,6 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const try js_env.bindGlobal(&window); // thanks to the arena, we don't need to deinit res. - var res: jsruntime.JSResult = undefined; const init = \\console = []; @@ -100,11 +99,7 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const \\ console.push("debug", ...arguments); \\}; ; - res = try evalJS(js_env, alloc, init, "init"); - if (!res.success) { - return res; - } - res.deinit(alloc); + _ = try evalJS(js_env, init, "init"); // loop hover the scripts. const doc = parser.documentHTMLToDocument(html_doc); @@ -121,22 +116,12 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const path = try fspath.join(alloc, &.{ "/", dirname, path }); } - res = try evalJS(js_env, alloc, try loader.get(path), src); - if (!res.success) { - return res; - } - res.deinit(alloc); + _ = try evalJS(js_env, try loader.get(path), src); } // If the script as a source text, execute it. const src = try parser.nodeTextContent(s) orelse continue; - res = try evalJS(js_env, alloc, src, ""); - - // return the first failure. - if (!res.success) { - return res; - } - res.deinit(alloc); + _ = try evalJS(js_env, src, ""); } // Mark tests as ready to run. @@ -150,25 +135,18 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const ); // wait for all async executions - res = try js_env.waitTryCatch(alloc); - if (!res.success) { - return res; - } - res.deinit(alloc); + _ = try js_env.wait(); // Check the final test status. - res = try evalJS(js_env, alloc, "report.status;", "teststatus"); - if (!res.success) { - return res; - } - res.deinit(alloc); + _ = try evalJS(js_env, "report.status;", "teststatus"); // return the detailed result. - return try evalJS(js_env, alloc, "report.log", "teststatus"); + const res = try evalJS(js_env, "report.log", "teststatus"); + return try res.toString(alloc, js_env); } -fn evalJS(env: jsruntime.Env, alloc: std.mem.Allocator, script: []const u8, name: ?[]const u8) !jsruntime.JSResult { - return try env.execTryCatch(alloc, script, name); +fn evalJS(env: jsruntime.Env, script: []const u8, name: ?[]const u8) !jsruntime.JSValue { + return try env.exec(script, name); } // browse the path to find the tests list. diff --git a/vendor/zig-js-runtime b/vendor/zig-js-runtime index a820cf43..e7fd4b1e 160000 --- a/vendor/zig-js-runtime +++ b/vendor/zig-js-runtime @@ -1 +1 @@ -Subproject commit a820cf4387d3607b2ea499ff8f5878a8ad79fe2e +Subproject commit e7fd4b1e04de56a3da3ef1169c321ad1b7e72a2e From 4434e11bddc7178aa99fa10911fd0b32a6839957 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Thu, 18 Jul 2024 16:40:00 +0200 Subject: [PATCH 2/4] wpt: restore the test results --- src/main_wpt.zig | 5 ++-- src/wpt/run.zig | 71 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/main_wpt.zig b/src/main_wpt.zig index aae1984c..c19598b2 100644 --- a/src/main_wpt.zig +++ b/src/main_wpt.zig @@ -141,7 +141,7 @@ pub fn main() !void { var arena = std.heap.ArenaAllocator.init(alloc); defer arena.deinit(); - const result = wpt.run(&arena, wpt_dir, tc, &loader) catch |err| { + const res = wpt.run(&arena, wpt_dir, tc, &loader) catch |err| { const suite = try Suite.init(alloc, tc, false, @errorName(err), null); try results.append(suite); @@ -151,8 +151,9 @@ pub fn main() !void { failures += 1; continue; }; + defer res.deinit(arena.allocator()); - const suite = try Suite.init(alloc, tc, true, result, null); + const suite = try Suite.init(alloc, tc, res.ok, res.msg orelse "", null); try results.append(suite); if (out == .json) { diff --git a/src/wpt/run.zig b/src/wpt/run.zig index 50c6eebe..6a503e66 100644 --- a/src/wpt/run.zig +++ b/src/wpt/run.zig @@ -36,7 +36,7 @@ const Client = @import("../async/Client.zig"); // runWPT parses the given HTML file, starts a js env and run the first script // tags containing javascript sources. // It loads first the js libs files. -pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const u8, loader: *FileLoader) ![]const u8 { +pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const u8, loader: *FileLoader) !Res { const alloc = arena.allocator(); try parser.init(); defer parser.deinit(); @@ -75,10 +75,11 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const // display console logs defer { - const res = evalJS(js_env, "console.join('\\n');", "console") catch unreachable; - const res_str = res.toString(alloc, js_env) catch unreachable; - if (res_str.len > 0) { - std.debug.print("-- CONSOLE LOG\n{s}\n--\n", .{res_str}); + const res = evalJS(js_env, alloc, "console.join('\\n');", "console") catch unreachable; + defer res.deinit(alloc); + + if (res.msg != null and res.msg.?.len > 0) { + std.debug.print("-- CONSOLE LOG\n{s}\n--\n", .{res.msg.?}); } } @@ -88,8 +89,6 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const window.setStorageShelf(&storageShelf); try js_env.bindGlobal(&window); - // thanks to the arena, we don't need to deinit res. - const init = \\console = []; \\console.log = function () { @@ -99,7 +98,9 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const \\ console.push("debug", ...arguments); \\}; ; - _ = try evalJS(js_env, init, "init"); + var res = try evalJS(js_env, alloc, init, "init"); + if (!res.ok) return res; + res.deinit(alloc); // loop hover the scripts. const doc = parser.documentHTMLToDocument(html_doc); @@ -116,12 +117,16 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const path = try fspath.join(alloc, &.{ "/", dirname, path }); } - _ = try evalJS(js_env, try loader.get(path), src); + res = try evalJS(js_env, alloc, try loader.get(path), src); + if (!res.ok) return res; + res.deinit(alloc); } // If the script as a source text, execute it. const src = try parser.nodeTextContent(s) orelse continue; - _ = try evalJS(js_env, src, ""); + res = try evalJS(js_env, alloc, src, ""); + if (!res.ok) return res; + res.deinit(alloc); } // Mark tests as ready to run. @@ -135,18 +140,52 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const ); // wait for all async executions - _ = try js_env.wait(); + var try_catch: jsruntime.TryCatch = undefined; + try_catch.init(js_env); + defer try_catch.deinit(); + js_env.wait() catch { + return .{ + .ok = false, + .msg = try try_catch.err(alloc, js_env), + }; + }; // Check the final test status. - _ = try evalJS(js_env, "report.status;", "teststatus"); + res = try evalJS(js_env, alloc, "report.status;", "teststatus"); + if (!res.ok) return res; + res.deinit(alloc); // return the detailed result. - const res = try evalJS(js_env, "report.log", "teststatus"); - return try res.toString(alloc, js_env); + return try evalJS(js_env, alloc, "report.log", "teststatus"); } -fn evalJS(env: jsruntime.Env, script: []const u8, name: ?[]const u8) !jsruntime.JSValue { - return try env.exec(script, name); +pub const Res = struct { + ok: bool, + msg: ?[]const u8, + + pub fn deinit(res: Res, alloc: std.mem.Allocator) void { + if (res.msg) |msg| { + alloc.free(msg); + } + } +}; + +fn evalJS(env: jsruntime.Env, alloc: std.mem.Allocator, script: []const u8, name: ?[]const u8) !Res { + var try_catch: jsruntime.TryCatch = undefined; + try_catch.init(env); + defer try_catch.deinit(); + + const v = env.exec(script, name) catch { + return .{ + .ok = false, + .msg = try try_catch.err(alloc, env), + }; + }; + + return .{ + .ok = true, + .msg = try v.toString(alloc, env), + }; } // browse the path to find the tests list. From b537e52a6dbf73882f0ba193da4275e228a01411 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Thu, 18 Jul 2024 16:46:12 +0200 Subject: [PATCH 3/4] browser: use log instead of std.log --- src/browser/browser.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/browser.zig b/src/browser/browser.zig index 9d530eac..b2a3d350 100644 --- a/src/browser/browser.zig +++ b/src/browser/browser.zig @@ -208,7 +208,7 @@ pub const Page = struct { const alloc = self.arena.allocator(); if (try try_catch.err(alloc, self.session.env)) |msg| { defer alloc.free(msg); - std.log.info("wait error: {s}", .{msg}); + log.info("wait error: {s}", .{msg}); return; } }; From 8c3939b842dda616844c2518914f83591a4a8d77 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Thu, 18 Jul 2024 16:51:36 +0200 Subject: [PATCH 4/4] wpt: remove useless Suite.stack --- src/main_wpt.zig | 6 +++--- src/wpt/testcase.zig | 23 +++++------------------ 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/main_wpt.zig b/src/main_wpt.zig index c19598b2..c8790254 100644 --- a/src/main_wpt.zig +++ b/src/main_wpt.zig @@ -142,7 +142,7 @@ pub fn main() !void { defer arena.deinit(); const res = wpt.run(&arena, wpt_dir, tc, &loader) catch |err| { - const suite = try Suite.init(alloc, tc, false, @errorName(err), null); + const suite = try Suite.init(alloc, tc, false, @errorName(err)); try results.append(suite); if (out == .text) { @@ -153,7 +153,7 @@ pub fn main() !void { }; defer res.deinit(arena.allocator()); - const suite = try Suite.init(alloc, tc, res.ok, res.msg orelse "", null); + const suite = try Suite.init(alloc, tc, res.ok, res.msg orelse ""); try results.append(suite); if (out == .json) { @@ -196,7 +196,7 @@ pub fn main() !void { try cases.append(Case{ .pass = suite.pass, .name = suite.name, - .message = suite.stack orelse suite.message, + .message = suite.message, }); } diff --git a/src/wpt/testcase.zig b/src/wpt/testcase.zig index 6c006e4a..1f3e0915 100644 --- a/src/wpt/testcase.zig +++ b/src/wpt/testcase.zig @@ -67,28 +67,22 @@ pub const Suite = struct { pass: bool, name: []const u8, message: ?[]const u8, - stack: ?[]const u8, cases: ?[]Case, // caller owns the wpt.Suite. // owner must call deinit(). - pub fn init(alloc: std.mem.Allocator, name: []const u8, pass: bool, res: []const u8, stack: ?[]const u8) !Suite { + pub fn init(alloc: std.mem.Allocator, name: []const u8, pass: bool, res: []const u8) !Suite { var suite = Suite{ .alloc = alloc, .pass = false, .name = try alloc.dupe(u8, name), .message = null, - .stack = null, .cases = null, }; // handle JS error. if (!pass) { suite.message = try alloc.dupe(u8, res); - if (stack) |st| { - suite.stack = try alloc.dupe(u8, st); - } - return suite; } @@ -155,10 +149,6 @@ pub const Suite = struct { pub fn deinit(self: Suite) void { self.alloc.free(self.name); - if (self.stack) |stack| { - self.alloc.free(stack); - } - if (self.message) |res| { self.alloc.free(res); } @@ -175,9 +165,6 @@ pub const Suite = struct { if (self.message) |v| { return v; } - if (self.stack) |v| { - return v; - } return ""; } }; @@ -199,7 +186,7 @@ test "success test case" { , }; - const suite = Suite.init(alloc, "foo", res.pass, res.result, null) catch unreachable; // TODO + const suite = Suite.init(alloc, "foo", res.pass, res.result) catch unreachable; // TODO defer suite.deinit(); try testing.expect(suite.pass == true); @@ -226,7 +213,7 @@ test "failed test case" { , }; - const suite = Suite.init(alloc, "foo", res.pass, res.result, null) catch unreachable; // TODO + const suite = Suite.init(alloc, "foo", res.pass, res.result) catch unreachable; // TODO defer suite.deinit(); try testing.expect(suite.pass == false); @@ -251,7 +238,7 @@ test "invalid result" { , }; - const suite = Suite.init(alloc, "foo", res.pass, res.result, null) catch unreachable; // TODO + const suite = Suite.init(alloc, "foo", res.pass, res.result) catch unreachable; // TODO defer suite.deinit(); try testing.expect(suite.pass == false); @@ -266,7 +253,7 @@ test "invalid result" { , }; - const suite2 = Suite.init(alloc, "foo", res2.pass, res2.result, null) catch unreachable; // TODO + const suite2 = Suite.init(alloc, "foo", res2.pass, res2.result) catch unreachable; // TODO defer suite2.deinit(); try testing.expect(suite2.pass == false);