mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
Poor support for functions/namespaces.
If you look at the specification for `console` [1], you'll note that it's a
namespace, not an interface (like most things). Furthermore, MDN lists its
methods as "static".
But it's a pretty weird namespace IMO, because some of its "functions", like
`count` can have state associated with them.
This causes some problems with our current implementation. Something like:
```
[1].forEach(console.log)
```
Fails, since `this` isn't our window-attached Console instance.
This commit introducing a new `static_XYZ` naming convention which does not
have the class/Self as a receiver:
```
pub fn static_log(values: []JsObject, page: *Page) !void {
```
This turns Console into a namespace for these specific functions, while still
being used normally for those functions that require state.
We could infer this behavior from the first parameter, but that seems more
error prone. For now, I prefer having the explicit `static_` prefix.
[1] https://console.spec.whatwg.org/#console-namespace
This commit is contained in:
@@ -30,46 +30,46 @@ pub const Console = struct {
|
|||||||
timers: std.StringHashMapUnmanaged(u32) = .{},
|
timers: std.StringHashMapUnmanaged(u32) = .{},
|
||||||
counts: std.StringHashMapUnmanaged(u32) = .{},
|
counts: std.StringHashMapUnmanaged(u32) = .{},
|
||||||
|
|
||||||
pub fn _lp(_: *const Console, values: []JsObject, page: *Page) !void {
|
pub fn static_lp(values: []JsObject, page: *Page) !void {
|
||||||
if (values.len == 0) {
|
if (values.len == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.fatal(.console, "lightpanda", .{ .args = try serializeValues(values, page) });
|
log.fatal(.console, "lightpanda", .{ .args = try serializeValues(values, page) });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _log(_: *const Console, values: []JsObject, page: *Page) !void {
|
pub fn static_log(values: []JsObject, page: *Page) !void {
|
||||||
if (values.len == 0) {
|
if (values.len == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.info(.console, "info", .{ .args = try serializeValues(values, page) });
|
log.info(.console, "info", .{ .args = try serializeValues(values, page) });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _info(console: *const Console, values: []JsObject, page: *Page) !void {
|
pub fn static_info(values: []JsObject, page: *Page) !void {
|
||||||
return console._log(values, page);
|
return static_log(values, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _debug(_: *const Console, values: []JsObject, page: *Page) !void {
|
pub fn static_debug(values: []JsObject, page: *Page) !void {
|
||||||
if (values.len == 0) {
|
if (values.len == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.debug(.console, "debug", .{ .args = try serializeValues(values, page) });
|
log.debug(.console, "debug", .{ .args = try serializeValues(values, page) });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _warn(_: *const Console, values: []JsObject, page: *Page) !void {
|
pub fn static_warn(values: []JsObject, page: *Page) !void {
|
||||||
if (values.len == 0) {
|
if (values.len == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.warn(.console, "warn", .{ .args = try serializeValues(values, page) });
|
log.warn(.console, "warn", .{ .args = try serializeValues(values, page) });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _error(_: *const Console, values: []JsObject, page: *Page) !void {
|
pub fn static_error(values: []JsObject, page: *Page) !void {
|
||||||
if (values.len == 0) {
|
if (values.len == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.info(.console, "error", .{ .args = try serializeValues(values, page) });
|
log.info(.console, "error", .{ .args = try serializeValues(values, page) });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _clear(_: *const Console) void {}
|
pub fn static_clear() void {}
|
||||||
|
|
||||||
pub fn _count(self: *Console, label_: ?[]const u8, page: *Page) !void {
|
pub fn _count(self: *Console, label_: ?[]const u8, page: *Page) !void {
|
||||||
const label = label_ orelse "default";
|
const label = label_ orelse "default";
|
||||||
@@ -130,7 +130,7 @@ pub const Console = struct {
|
|||||||
log.warn(.console, "timer stop", .{ .label = label, .elapsed = elapsed - kv.value });
|
log.warn(.console, "timer stop", .{ .label = label, .elapsed = elapsed - kv.value });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _assert(_: *Console, assertion: JsObject, values: []JsObject, page: *Page) !void {
|
pub fn static_assert(assertion: JsObject, values: []JsObject, page: *Page) !void {
|
||||||
if (assertion.isTruthy()) {
|
if (assertion.isTruthy()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -225,7 +225,18 @@ test "Browser.Console" {
|
|||||||
try testing.expectEqual("[assertion failed] values= 1: x 2: true", captured[1]);
|
try testing.expectEqual("[assertion failed] values= 1: x 2: true", captured[1]);
|
||||||
try testing.expectEqual("[assertion failed] values= 1: x", captured[2]);
|
try testing.expectEqual("[assertion failed] values= 1: x", captured[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
test_capture.reset();
|
||||||
|
try runner.testCases(&.{
|
||||||
|
.{ "[1].forEach(console.log)", null },
|
||||||
|
}, .{});
|
||||||
|
|
||||||
|
const captured = test_capture.captured.items;
|
||||||
|
try testing.expectEqual("[info] args= 1: 1 2: 0 3: [1]", captured[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TestCapture = struct {
|
const TestCapture = struct {
|
||||||
captured: std.ArrayListUnmanaged([]const u8) = .{},
|
captured: std.ArrayListUnmanaged([]const u8) = .{},
|
||||||
|
|
||||||
|
|||||||
@@ -1680,6 +1680,8 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
}
|
}
|
||||||
} else if (comptime std.mem.startsWith(u8, name, "get_")) {
|
} else if (comptime std.mem.startsWith(u8, name, "get_")) {
|
||||||
generateProperty(Struct, name[4..], isolate, template_proto);
|
generateProperty(Struct, name[4..], isolate, template_proto);
|
||||||
|
} else if (comptime std.mem.startsWith(u8, name, "static_")) {
|
||||||
|
generateFunction(Struct, name[7..], isolate, template_proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1769,6 +1771,23 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
template_proto.set(js_name, function_template, v8.PropertyAttribute.None);
|
template_proto.set(js_name, function_template, v8.PropertyAttribute.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generateFunction(comptime Struct: type, comptime name: []const u8, isolate: v8.Isolate, template_proto: v8.ObjectTemplate) void {
|
||||||
|
const js_name = v8.String.initUtf8(isolate, name).toName();
|
||||||
|
const function_template = v8.FunctionTemplate.initCallback(isolate, struct {
|
||||||
|
fn callback(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
||||||
|
const info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
||||||
|
var caller = Caller(Self, State).init(info);
|
||||||
|
defer caller.deinit();
|
||||||
|
|
||||||
|
const named_function = comptime NamedFunction.init(Struct, "static_" ++ name);
|
||||||
|
caller.function(Struct, named_function, info) catch |err| {
|
||||||
|
caller.handleError(Struct, named_function, err, info);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}.callback);
|
||||||
|
template_proto.set(js_name, function_template, v8.PropertyAttribute.None);
|
||||||
|
}
|
||||||
|
|
||||||
fn generateAttribute(comptime Struct: type, comptime name: []const u8, isolate: v8.Isolate, template: v8.FunctionTemplate, template_proto: v8.ObjectTemplate) void {
|
fn generateAttribute(comptime Struct: type, comptime name: []const u8, isolate: v8.Isolate, template: v8.FunctionTemplate, template_proto: v8.ObjectTemplate) void {
|
||||||
const zig_value = @field(Struct, name);
|
const zig_value = @field(Struct, name);
|
||||||
const js_value = simpleZigValueToJs(isolate, zig_value, true);
|
const js_value = simpleZigValueToJs(isolate, zig_value, true);
|
||||||
@@ -2154,6 +2173,8 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
return @ptrFromInt(@intFromPtr(toa.ptr) + @as(usize, @intCast(offset)));
|
return @ptrFromInt(@intFromPtr(toa.ptr) + @as(usize, @intCast(offset)));
|
||||||
}
|
}
|
||||||
if (prototype_index == type_index) {
|
if (prototype_index == type_index) {
|
||||||
|
// When a type has itself as the prototype, then we've
|
||||||
|
// reached the end of the chain.
|
||||||
return error.InvalidArgument;
|
return error.InvalidArgument;
|
||||||
}
|
}
|
||||||
type_index = prototype_index;
|
type_index = prototype_index;
|
||||||
@@ -2341,6 +2362,14 @@ fn Caller(comptime E: type, comptime State: type) type {
|
|||||||
info.getReturnValue().set(try scope.zigValueToJs(res));
|
info.getReturnValue().set(try scope.zigValueToJs(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn function(self: *Self, comptime Struct: type, comptime named_function: NamedFunction, info: v8.FunctionCallbackInfo) !void {
|
||||||
|
const scope = self.scope;
|
||||||
|
const func = @field(Struct, named_function.name);
|
||||||
|
const args = try self.getArgs(Struct, named_function, 0, info);
|
||||||
|
const res = @call(.auto, func, args);
|
||||||
|
info.getReturnValue().set(try scope.zigValueToJs(res));
|
||||||
|
}
|
||||||
|
|
||||||
fn getter(self: *Self, comptime Struct: type, comptime named_function: NamedFunction, info: v8.FunctionCallbackInfo) !void {
|
fn getter(self: *Self, comptime Struct: type, comptime named_function: NamedFunction, info: v8.FunctionCallbackInfo) !void {
|
||||||
const scope = self.scope;
|
const scope = self.scope;
|
||||||
const func = @field(Struct, named_function.name);
|
const func = @field(Struct, named_function.name);
|
||||||
|
|||||||
Reference in New Issue
Block a user