mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
backport some node_lexbor modifications
Signed-off-by: Francis Bouvier <francis.bouvier@gmail.com>
This commit is contained in:
14
src/dom.zig
14
src/dom.zig
@@ -4,12 +4,13 @@ const Console = @import("jsruntime").Console;
|
||||
|
||||
// DOM
|
||||
const EventTarget = @import("dom/event_target.zig").EventTarget;
|
||||
const Node = @import("dom/node.zig").Node;
|
||||
const N = @import("dom/node.zig");
|
||||
const Element = @import("dom/element.zig").Element;
|
||||
const Document = @import("dom/document.zig").Document;
|
||||
|
||||
// HTML
|
||||
pub const HTMLDocument = @import("html/document.zig").HTMLDocument;
|
||||
const HTMLElem = @import("html/elements.zig");
|
||||
|
||||
const E = @import("html/elements.zig");
|
||||
|
||||
@@ -19,14 +20,15 @@ const interfaces = .{
|
||||
|
||||
// DOM
|
||||
EventTarget,
|
||||
Node,
|
||||
N.Node,
|
||||
N.Types,
|
||||
Element,
|
||||
Document,
|
||||
|
||||
// HTML
|
||||
HTMLDocument,
|
||||
E.HTMLElement,
|
||||
E.HTMLMediaElement,
|
||||
E.HTMLElementsTypes,
|
||||
HTMLElem.HTMLElement,
|
||||
HTMLElem.HTMLMediaElement,
|
||||
HTMLElem.Types,
|
||||
};
|
||||
pub const Interfaces = generate.TupleInst(generate.TupleT(interfaces), interfaces);
|
||||
pub const Interfaces = generate.Tuple(interfaces);
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
const std = @import("std");
|
||||
|
||||
const generate = @import("../generate.zig");
|
||||
|
||||
const parser = @import("../netsurf.zig");
|
||||
|
||||
const EventTarget = @import("event_target.zig").EventTarget;
|
||||
const HTMLDocument = @import("../html/document.zig").HTMLDocument;
|
||||
const HTMLElem = @import("../html/elements.zig");
|
||||
|
||||
pub const Node = struct {
|
||||
pub const Self = parser.Node;
|
||||
pub const prototype = *EventTarget;
|
||||
pub const mem_guarantied = true;
|
||||
};
|
||||
|
||||
pub const Types = generate.Tuple(.{
|
||||
HTMLElem.Types,
|
||||
HTMLDocument,
|
||||
});
|
||||
const Generated = generate.Union.compile(Types);
|
||||
pub const Union = Generated._union;
|
||||
pub const Tags = Generated._enum;
|
||||
|
||||
189
src/generate.zig
189
src/generate.zig
@@ -1,13 +1,33 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
// Utils
|
||||
// -----
|
||||
|
||||
fn itoa(comptime i: u8) ![]u8 {
|
||||
var len: usize = undefined;
|
||||
if (i < 10) {
|
||||
len = 1;
|
||||
} else if (i < 100) {
|
||||
len = 2;
|
||||
} else {
|
||||
return error.GenerateTooMuchMembers;
|
||||
}
|
||||
var buf: [len]u8 = undefined;
|
||||
return try std.fmt.bufPrint(buf[0..], "{d}", .{i});
|
||||
}
|
||||
|
||||
fn fmtName(comptime T: type) []const u8 {
|
||||
var it = std.mem.splitBackwards(u8, @typeName(T), ".");
|
||||
return it.first();
|
||||
}
|
||||
|
||||
// Union
|
||||
// -----
|
||||
|
||||
// Generate a flatten tagged Union from various structs and union of structs
|
||||
// TODO: make this function more generic
|
||||
// TODO: dedup
|
||||
pub const Union = struct {
|
||||
_enum: type,
|
||||
_union: type,
|
||||
@@ -152,38 +172,15 @@ pub const Union = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn itoa(comptime i: u8) ![]u8 {
|
||||
var len: usize = undefined;
|
||||
if (i < 10) {
|
||||
len = 1;
|
||||
} else if (i < 100) {
|
||||
len = 2;
|
||||
} else {
|
||||
return error.GenerateTooMuchMembers;
|
||||
}
|
||||
var buf: [len]u8 = undefined;
|
||||
return try std.fmt.bufPrint(buf[0..], "{d}", .{i});
|
||||
}
|
||||
// Tuple
|
||||
// -----
|
||||
|
||||
// Generate a flatten tuple type from various structs and tuple of structs.
|
||||
// TODO: make this function more generic
|
||||
pub fn TupleT(comptime tuple: anytype) type {
|
||||
|
||||
// check types provided
|
||||
const tuple_T = @TypeOf(tuple);
|
||||
const tuple_info = @typeInfo(tuple_T);
|
||||
if (tuple_info != .Struct or !tuple_info.Struct.is_tuple) {
|
||||
@compileError("GenerateArgNotTuple");
|
||||
}
|
||||
|
||||
const tuple_members = tuple_info.Struct.fields;
|
||||
|
||||
// first iteration to get the total number of members
|
||||
var members_nb = 0;
|
||||
for (tuple_members) |member| {
|
||||
fn tupleNb(comptime tuple: anytype) usize {
|
||||
var nb = 0;
|
||||
for (@typeInfo(@TypeOf(tuple)).Struct.fields) |member| {
|
||||
const member_T = @field(tuple, member.name);
|
||||
if (@TypeOf(member_T) == type) {
|
||||
members_nb += 1;
|
||||
nb += 1;
|
||||
} else {
|
||||
const member_info = @typeInfo(@TypeOf(member_T));
|
||||
if (member_info != .Struct and !member_info.Struct.is_tuple) {
|
||||
@@ -194,14 +191,82 @@ pub fn TupleT(comptime tuple: anytype) type {
|
||||
@compileError("GenerateMemberTupleChildNotType");
|
||||
}
|
||||
}
|
||||
members_nb += member_info.Struct.fields.len;
|
||||
nb += member_info.Struct.fields.len;
|
||||
}
|
||||
}
|
||||
return nb;
|
||||
}
|
||||
|
||||
// second iteration to generate the tuple type
|
||||
var fields: [members_nb]std.builtin.Type.StructField = undefined;
|
||||
fn tupleTypes(comptime nb: usize, comptime tuple: anytype) [nb]type {
|
||||
var types: [nb]type = undefined;
|
||||
var done = 0;
|
||||
while (done < members_nb) {
|
||||
for (@typeInfo(@TypeOf(tuple)).Struct.fields) |member| {
|
||||
const T = @field(tuple, member.name);
|
||||
if (@TypeOf(T) == type) {
|
||||
types[done] = T;
|
||||
done += 1;
|
||||
} else {
|
||||
const info = @typeInfo(@TypeOf(T));
|
||||
for (info.Struct.fields) |field| {
|
||||
types[done] = @field(T, field.name);
|
||||
done += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
fn isDup(comptime nb: usize, comptime list: [nb]type, comptime T: type, comptime i: usize) bool {
|
||||
for (list, 0..) |item, index| {
|
||||
if (i >= index) {
|
||||
// check sequentially
|
||||
continue;
|
||||
}
|
||||
if (T == item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn dedupIndexes(comptime nb: usize, comptime types: [nb]type) [nb]i32 {
|
||||
var dedup_indexes: [nb]i32 = undefined;
|
||||
for (types, 0..) |T, i| {
|
||||
if (isDup(nb, types, T, i)) {
|
||||
dedup_indexes[i] = -1;
|
||||
} else {
|
||||
dedup_indexes[i] = i;
|
||||
}
|
||||
}
|
||||
return dedup_indexes;
|
||||
}
|
||||
|
||||
fn dedupNb(comptime nb: usize, comptime dedup_indexes: [nb]i32) usize {
|
||||
var dedup_nb = 0;
|
||||
for (dedup_indexes) |index| {
|
||||
if (index != -1) {
|
||||
dedup_nb += 1;
|
||||
}
|
||||
}
|
||||
return dedup_nb;
|
||||
}
|
||||
|
||||
fn TupleT(comptime tuple: anytype) type {
|
||||
@setEvalBranchQuota(100000);
|
||||
|
||||
// logic
|
||||
const nb = tupleNb(tuple);
|
||||
const types = tupleTypes(nb, tuple);
|
||||
const dedup_indexes = dedupIndexes(nb, types);
|
||||
const dedup_nb = dedupNb(nb, dedup_indexes);
|
||||
|
||||
// generate the tuple type
|
||||
var fields: [dedup_nb]std.builtin.Type.StructField = undefined;
|
||||
var done = 0;
|
||||
for (dedup_indexes) |index| {
|
||||
if (index == -1) {
|
||||
continue;
|
||||
}
|
||||
fields[done] = .{
|
||||
.name = try itoa(done),
|
||||
.type = type,
|
||||
@@ -221,39 +286,36 @@ pub fn TupleT(comptime tuple: anytype) type {
|
||||
return @Type(std.builtin.Type{ .Struct = info });
|
||||
}
|
||||
|
||||
// Instantiate a flatten tuple from various structs and tuple of structs
|
||||
// You need to call first TupleT to generate the according type
|
||||
// Create a flatten tuple from various structs and tuple of structs
|
||||
// Duplicates will be removed.
|
||||
// TODO: make this function more generic
|
||||
pub fn TupleInst(comptime T: type, comptime tuple: anytype) T {
|
||||
pub fn Tuple(comptime tuple: anytype) TupleT(tuple) {
|
||||
|
||||
// check types provided
|
||||
const tuple_T = @TypeOf(tuple);
|
||||
const tuple_info = @typeInfo(tuple_T);
|
||||
const tuple_members = tuple_info.Struct.fields;
|
||||
if (tuple_info != .Struct or !tuple_info.Struct.is_tuple) {
|
||||
@compileError("GenerateArgNotTuple");
|
||||
}
|
||||
|
||||
// generate the type
|
||||
const T = TupleT(tuple);
|
||||
|
||||
// logic
|
||||
const nb = tupleNb(tuple);
|
||||
const types = tupleTypes(nb, tuple);
|
||||
const dedup_indexes = dedupIndexes(nb, types);
|
||||
|
||||
// instantiate the tuple
|
||||
var t: T = undefined;
|
||||
var done = 0;
|
||||
for (tuple_members) |member| {
|
||||
const member_T = @field(tuple, member.name);
|
||||
var member_info: std.builtin.Type = undefined;
|
||||
if (@TypeOf(member_T) == type) {
|
||||
member_info = @typeInfo(member_T);
|
||||
} else {
|
||||
member_info = @typeInfo(@TypeOf(member_T));
|
||||
}
|
||||
var member_detail = member_info.Struct;
|
||||
if (member_detail.is_tuple) {
|
||||
for (member_detail.fields) |field| {
|
||||
const name = try itoa(done);
|
||||
@field(t, name) = @field(member_T, field.name);
|
||||
done += 1;
|
||||
}
|
||||
} else {
|
||||
const name = try itoa(done);
|
||||
@field(t, name) = @field(tuple, member.name);
|
||||
done += 1;
|
||||
for (dedup_indexes) |index| {
|
||||
if (index == -1) {
|
||||
continue;
|
||||
}
|
||||
const name = try itoa(done);
|
||||
@field(t, name) = types[index];
|
||||
done += 1;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
@@ -322,7 +384,7 @@ pub fn tests() !void {
|
||||
|
||||
// Tuple from structs
|
||||
const tuple_structs = .{ Astruct, Bstruct };
|
||||
const tFromStructs = TupleInst(TupleT(tuple_structs), tuple_structs);
|
||||
const tFromStructs = Tuple(tuple_structs);
|
||||
const t_from_structs = @typeInfo(@TypeOf(tFromStructs));
|
||||
try std.testing.expect(t_from_structs == .Struct);
|
||||
try std.testing.expect(t_from_structs.Struct.is_tuple);
|
||||
@@ -332,7 +394,7 @@ pub fn tests() !void {
|
||||
|
||||
// Tuple from tuple and structs
|
||||
const tuple_mix = .{ tFromStructs, Cstruct };
|
||||
const tFromMix = TupleInst(TupleT(tuple_mix), tuple_mix);
|
||||
const tFromMix = Tuple(tuple_mix);
|
||||
const t_from_mix = @typeInfo(@TypeOf(tFromMix));
|
||||
try std.testing.expect(t_from_mix == .Struct);
|
||||
try std.testing.expect(t_from_mix.Struct.is_tuple);
|
||||
@@ -341,5 +403,16 @@ pub fn tests() !void {
|
||||
try std.testing.expect(@field(tFromMix, "1") == Bstruct);
|
||||
try std.testing.expect(@field(tFromMix, "2") == Cstruct);
|
||||
|
||||
// Tuple with dedup
|
||||
const tuple_dedup = .{ Cstruct, Astruct, tFromStructs, Bstruct };
|
||||
const tFromDedup = Tuple(tuple_dedup);
|
||||
const t_from_dedup = @typeInfo(@TypeOf(tFromDedup));
|
||||
try std.testing.expect(t_from_dedup == .Struct);
|
||||
try std.testing.expect(t_from_dedup.Struct.is_tuple);
|
||||
try std.testing.expect(t_from_dedup.Struct.fields.len == 3);
|
||||
try std.testing.expect(@field(tFromDedup, "0") == Cstruct);
|
||||
try std.testing.expect(@field(tFromDedup, "1") == Astruct);
|
||||
try std.testing.expect(@field(tFromDedup, "2") == Bstruct);
|
||||
|
||||
std.debug.print("Generate Tuple: OK\n", .{});
|
||||
}
|
||||
|
||||
@@ -7,8 +7,7 @@ const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
|
||||
const Document = @import("../dom/document.zig").Document;
|
||||
|
||||
const E = @import("elements.zig");
|
||||
const HTMLElem = @import("elements.zig");
|
||||
|
||||
pub const HTMLDocument = struct {
|
||||
pub const Self = parser.DocumentHTML;
|
||||
@@ -22,19 +21,19 @@ pub const HTMLDocument = struct {
|
||||
return parser.documentHTMLBody(self);
|
||||
}
|
||||
|
||||
pub fn _getElementById(self: *parser.DocumentHTML, id: []u8) ?*parser.ElementHTML {
|
||||
pub fn _getElementById(self: *parser.DocumentHTML, id: []u8) ?HTMLElem.Union {
|
||||
const doc = parser.documentHTMLToDocument(self);
|
||||
const elem = parser.documentGetElementById(doc, id);
|
||||
if (elem) |value| {
|
||||
return @as(*parser.ElementHTML, @ptrCast(value));
|
||||
const elem_dom = parser.documentGetElementById(doc, id);
|
||||
if (elem_dom) |elem| {
|
||||
return HTMLElem.toInterface(HTMLElem.Union, elem);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn _createElement(self: *parser.DocumentHTML, tag_name: []const u8) E.HTMLElements {
|
||||
pub fn _createElement(self: *parser.DocumentHTML, tag_name: []const u8) HTMLElem.Union {
|
||||
const doc_dom = parser.documentHTMLToDocument(self);
|
||||
const base = parser.documentCreateElement(doc_dom, tag_name);
|
||||
return E.ElementToHTMLElementInterface(base);
|
||||
return HTMLElem.toInterface(HTMLElem.Union, base);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -51,13 +50,14 @@ pub fn testExecFn(
|
||||
.{ .src = "document.__proto__.__proto__.constructor.name", .ex = "Document" },
|
||||
.{ .src = "document.__proto__.__proto__.__proto__.constructor.name", .ex = "Node" },
|
||||
.{ .src = "document.__proto__.__proto__.__proto__.__proto__.constructor.name", .ex = "EventTarget" },
|
||||
.{ .src = "document.body.localName === 'body'", .ex = "true" },
|
||||
};
|
||||
try checkCases(js_env, &constructor);
|
||||
|
||||
var getElementById = [_]Case{
|
||||
.{ .src = "let getElementById = document.getElementById('content')", .ex = "undefined" },
|
||||
.{ .src = "getElementById.constructor.name", .ex = "HTMLElement" },
|
||||
.{ .src = "getElementById.localName", .ex = "main" },
|
||||
.{ .src = "getElementById.constructor.name", .ex = "HTMLDivElement" },
|
||||
.{ .src = "getElementById.localName", .ex = "div" },
|
||||
};
|
||||
try checkCases(js_env, &getElementById);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ pub const HTMLElement = struct {
|
||||
pub const mem_guarantied = true;
|
||||
};
|
||||
|
||||
pub const HTMLElementsTypes = .{
|
||||
pub const Types = .{
|
||||
HTMLUnknownElement,
|
||||
HTMLAnchorElement,
|
||||
HTMLAreaElement,
|
||||
@@ -74,9 +74,9 @@ pub const HTMLElementsTypes = .{
|
||||
HTMLUListElement,
|
||||
HTMLVideoElement,
|
||||
};
|
||||
const HTMLElementsGenerated = generate.Union.compile(HTMLElementsTypes);
|
||||
pub const HTMLElements = HTMLElementsGenerated._union;
|
||||
pub const HTMLElementsTags = HTMLElementsGenerated._enum;
|
||||
const Generated = generate.Union.compile(Types);
|
||||
pub const Union = Generated._union;
|
||||
pub const Tags = Generated._enum;
|
||||
|
||||
// Deprecated HTMLElements in Chrome (2023/03/15)
|
||||
// HTMLContentelement
|
||||
@@ -454,7 +454,7 @@ pub const HTMLVideoElement = struct {
|
||||
pub const mem_guarantied = true;
|
||||
};
|
||||
|
||||
pub fn ElementToHTMLElementInterface(elem: *parser.Element) HTMLElements {
|
||||
pub fn toInterface(comptime T: type, elem: *parser.Element) T {
|
||||
const tag = parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(elem)));
|
||||
return switch (tag) {
|
||||
.a => .{ .HTMLAnchorElement = @as(*parser.Anchor, @ptrCast(elem)) },
|
||||
|
||||
Reference in New Issue
Block a user