Merge pull request #253 from lightpanda-io/refacto_exec

Adapt to js_exec changes in zig-js-runtime
This commit is contained in:
Pierre Tachoire
2024-07-18 16:56:41 +02:00
committed by GitHub
8 changed files with 113 additions and 95 deletions

View File

@@ -198,21 +198,21 @@ pub const Page = struct {
} }
pub fn wait(self: *Page) !void { 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) { // try catch
log.debug("wait: {s}", .{res.result}); var try_catch: jsruntime.TryCatch = undefined;
} else { try_catch.init(self.session.env);
if (builtin.mode == .Debug and res.stack != null) { defer try_catch.deinit();
log.info("wait: {s}", .{res.stack.?});
} else { self.session.env.wait() catch {
log.info("wait: {s}", .{res.result}); const alloc = self.arena.allocator();
if (try try_catch.err(alloc, self.session.env)) |msg| {
defer alloc.free(msg);
log.info("wait error: {s}", .{msg});
return;
} }
} };
log.debug("wait: OK", .{});
return;
} }
// spec reference: https://html.spec.whatwg.org/#document-lifecycle // spec reference: https://html.spec.whatwg.org/#document-lifecycle
@@ -322,7 +322,7 @@ pub const Page = struct {
// start JS env // start JS env
// TODO load the js env concurrently with the HTML parsing. // TODO load the js env concurrently with the HTML parsing.
log.debug("start js env", .{}); 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. // replace the user context document with the new one.
try self.session.env.setUserContext(.{ try self.session.env.setUserContext(.{
@@ -473,22 +473,26 @@ pub const Page = struct {
return; 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)); const opt_text = try parser.nodeTextContent(parser.elementToNode(e));
if (opt_text) |text| { if (opt_text) |text| {
// TODO handle charset attribute // TODO handle charset attribute
var res = try self.session.env.execTryCatch(alloc, text, ""); const res = self.session.env.exec(text, "") catch {
defer res.deinit(alloc); if (try try_catch.err(alloc, self.session.env)) |msg| {
defer alloc.free(msg);
if (res.success) { log.info("eval inline {s}: {s}", .{ text, msg });
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});
} }
} 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; return;
} }
@@ -530,18 +534,22 @@ pub const Page = struct {
// check no body // check no body
if (body.len == 0) return FetchError.NoBody; if (body.len == 0) return FetchError.NoBody;
var res = try self.session.env.execTryCatch(alloc, body, src); var try_catch: jsruntime.TryCatch = undefined;
defer res.deinit(alloc); try_catch.init(self.session.env);
defer try_catch.deinit();
if (res.success) { const res = self.session.env.exec(body, src) catch {
log.debug("eval remote {s}: {s}", .{ src, res.result }); if (try try_catch.err(alloc, self.session.env)) |msg| {
} else { defer alloc.free(msg);
if (builtin.mode == .Debug and res.stack != null) { log.info("eval remote {s}: {s}", .{ src, msg });
log.info("eval remote {s}: {s}", .{ src, res.stack.? });
} else {
log.info("eval remote {s}: {s}", .{ src, res.result });
} }
return FetchError.JsErr; 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 });
} }
} }

View File

@@ -37,7 +37,7 @@ fn execJS(
js_env: *jsruntime.Env, js_env: *jsruntime.Env,
) anyerror!void { ) anyerror!void {
// start JS env // start JS env
try js_env.start(alloc); try js_env.start();
defer js_env.stop(); defer js_env.stop();
// alias global as self and window // alias global as self and window
@@ -45,6 +45,11 @@ fn execJS(
window.replaceDocument(doc); window.replaceDocument(doc);
try js_env.bindGlobal(window); try js_env.bindGlobal(window);
// try catch
var try_catch: jsruntime.TryCatch = undefined;
try_catch.init(js_env.*);
defer try_catch.deinit();
while (true) { while (true) {
// read cmd // read cmd
@@ -57,11 +62,12 @@ fn execJS(
break; break;
} }
const res = try js_env.execTryCatch(alloc, cmd, "cdp"); const res = try js_env.exec(cmd, "cdp");
if (res.success) { const res_str = try res.toString(alloc, js_env.*);
std.debug.print("-> {s}\n", .{res.result}); defer alloc.free(res_str);
} std.debug.print("-> {s}\n", .{res_str});
_ = try conn.stream.write(res.result);
_ = try conn.stream.write(res_str);
} }
} }

View File

@@ -38,7 +38,7 @@ fn execJS(
js_env: *jsruntime.Env, js_env: *jsruntime.Env,
) anyerror!void { ) anyerror!void {
// start JS env // start JS env
try js_env.start(alloc); try js_env.start();
defer js_env.stop(); defer js_env.stop();
var cli = Client{ .allocator = alloc, .loop = js_env.nat_ctx.loop }; var cli = Client{ .allocator = alloc, .loop = js_env.nat_ctx.loop };

View File

@@ -142,7 +142,7 @@ pub fn main() !void {
defer arena.deinit(); defer arena.deinit();
const res = 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); const suite = try Suite.init(alloc, tc, false, @errorName(err));
try results.append(suite); try results.append(suite);
if (out == .text) { if (out == .text) {
@@ -151,9 +151,9 @@ pub fn main() !void {
failures += 1; failures += 1;
continue; continue;
}; };
// no need to call res.deinit() thanks to the arena allocator. defer res.deinit(arena.allocator());
const suite = try Suite.init(alloc, tc, res.success, res.result, res.stack); const suite = try Suite.init(alloc, tc, res.ok, res.msg orelse "");
try results.append(suite); try results.append(suite);
if (out == .json) { if (out == .json) {
@@ -196,7 +196,7 @@ pub fn main() !void {
try cases.append(Case{ try cases.append(Case{
.pass = suite.pass, .pass = suite.pass,
.name = suite.name, .name = suite.name,
.message = suite.stack orelse suite.message, .message = suite.message,
}); });
} }

View File

@@ -71,7 +71,7 @@ fn testExecFn(
defer parser.deinit(); defer parser.deinit();
// start JS env // start JS env
try js_env.start(alloc); try js_env.start();
defer js_env.stop(); defer js_env.stop();
var storageShelf = storage.Shelf.init(alloc); var storageShelf = storage.Shelf.init(alloc);

View File

@@ -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 // runWPT parses the given HTML file, starts a js env and run the first script
// tags containing javascript sources. // tags containing javascript sources.
// It loads first the js libs files. // 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) !Res {
const alloc = arena.allocator(); const alloc = arena.allocator();
try parser.init(); try parser.init();
defer parser.deinit(); defer parser.deinit();
@@ -70,15 +70,16 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const
try js_env.load(&js_types); try js_env.load(&js_types);
// start JS env // start JS env
try js_env.start(alloc); try js_env.start();
defer js_env.stop(); defer js_env.stop();
// display console logs // display console logs
defer { defer {
var res = evalJS(js_env, alloc, "console.join('\\n');", "console") catch unreachable; const res = evalJS(js_env, alloc, "console.join('\\n');", "console") catch unreachable;
defer res.deinit(alloc); defer res.deinit(alloc);
if (res.result.len > 0) {
std.debug.print("-- CONSOLE LOG\n{s}\n--\n", .{res.result}); if (res.msg != null and res.msg.?.len > 0) {
std.debug.print("-- CONSOLE LOG\n{s}\n--\n", .{res.msg.?});
} }
} }
@@ -88,9 +89,6 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const
window.setStorageShelf(&storageShelf); window.setStorageShelf(&storageShelf);
try js_env.bindGlobal(&window); try js_env.bindGlobal(&window);
// thanks to the arena, we don't need to deinit res.
var res: jsruntime.JSResult = undefined;
const init = const init =
\\console = []; \\console = [];
\\console.log = function () { \\console.log = function () {
@@ -100,10 +98,8 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const
\\ console.push("debug", ...arguments); \\ console.push("debug", ...arguments);
\\}; \\};
; ;
res = try evalJS(js_env, alloc, init, "init"); var res = try evalJS(js_env, alloc, init, "init");
if (!res.success) { if (!res.ok) return res;
return res;
}
res.deinit(alloc); res.deinit(alloc);
// loop hover the scripts. // loop hover the scripts.
@@ -122,20 +118,14 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const
} }
res = try evalJS(js_env, alloc, try loader.get(path), src); res = try evalJS(js_env, alloc, try loader.get(path), src);
if (!res.success) { if (!res.ok) return res;
return res;
}
res.deinit(alloc); res.deinit(alloc);
} }
// If the script as a source text, execute it. // If the script as a source text, execute it.
const src = try parser.nodeTextContent(s) orelse continue; const src = try parser.nodeTextContent(s) orelse continue;
res = try evalJS(js_env, alloc, src, ""); res = try evalJS(js_env, alloc, src, "");
if (!res.ok) return res;
// return the first failure.
if (!res.success) {
return res;
}
res.deinit(alloc); res.deinit(alloc);
} }
@@ -150,25 +140,52 @@ pub fn run(arena: *std.heap.ArenaAllocator, comptime dir: []const u8, f: []const
); );
// wait for all async executions // wait for all async executions
res = try js_env.waitTryCatch(alloc); var try_catch: jsruntime.TryCatch = undefined;
if (!res.success) { try_catch.init(js_env);
return res; defer try_catch.deinit();
} js_env.wait() catch {
res.deinit(alloc); return .{
.ok = false,
.msg = try try_catch.err(alloc, js_env),
};
};
// Check the final test status. // Check the final test status.
res = try evalJS(js_env, alloc, "report.status;", "teststatus"); res = try evalJS(js_env, alloc, "report.status;", "teststatus");
if (!res.success) { if (!res.ok) return res;
return res;
}
res.deinit(alloc); res.deinit(alloc);
// return the detailed result. // return the detailed result.
return try evalJS(js_env, alloc, "report.log", "teststatus"); return try evalJS(js_env, alloc, "report.log", "teststatus");
} }
fn evalJS(env: jsruntime.Env, alloc: std.mem.Allocator, script: []const u8, name: ?[]const u8) !jsruntime.JSResult { pub const Res = struct {
return try env.execTryCatch(alloc, script, name); 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. // browse the path to find the tests list.

View File

@@ -67,28 +67,22 @@ pub const Suite = struct {
pass: bool, pass: bool,
name: []const u8, name: []const u8,
message: ?[]const u8, message: ?[]const u8,
stack: ?[]const u8,
cases: ?[]Case, cases: ?[]Case,
// caller owns the wpt.Suite. // caller owns the wpt.Suite.
// owner must call deinit(). // 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{ var suite = Suite{
.alloc = alloc, .alloc = alloc,
.pass = false, .pass = false,
.name = try alloc.dupe(u8, name), .name = try alloc.dupe(u8, name),
.message = null, .message = null,
.stack = null,
.cases = null, .cases = null,
}; };
// handle JS error. // handle JS error.
if (!pass) { if (!pass) {
suite.message = try alloc.dupe(u8, res); suite.message = try alloc.dupe(u8, res);
if (stack) |st| {
suite.stack = try alloc.dupe(u8, st);
}
return suite; return suite;
} }
@@ -155,10 +149,6 @@ pub const Suite = struct {
pub fn deinit(self: Suite) void { pub fn deinit(self: Suite) void {
self.alloc.free(self.name); self.alloc.free(self.name);
if (self.stack) |stack| {
self.alloc.free(stack);
}
if (self.message) |res| { if (self.message) |res| {
self.alloc.free(res); self.alloc.free(res);
} }
@@ -175,9 +165,6 @@ pub const Suite = struct {
if (self.message) |v| { if (self.message) |v| {
return v; return v;
} }
if (self.stack) |v| {
return v;
}
return ""; 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(); defer suite.deinit();
try testing.expect(suite.pass == true); 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(); defer suite.deinit();
try testing.expect(suite.pass == false); 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(); defer suite.deinit();
try testing.expect(suite.pass == false); 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(); defer suite2.deinit();
try testing.expect(suite2.pass == false); try testing.expect(suite2.pass == false);