mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
Tweak generate.Tuple and generate.Union
Leverage comptime fields to give generated Tuple a default value, allowing TupleT and Tuple to be merged. Only call generate.Tuple on the final output. This eliminates redundant deduplication, and results in a simpler API (nested types just need to expose a natural Zig tuple). generate.Union leverages the new Tuple and removes unused features.
This commit is contained in:
@@ -42,6 +42,6 @@ pub const Interfaces = generate.Tuple(.{
|
|||||||
URL.Interfaces,
|
URL.Interfaces,
|
||||||
Iterators.Interfaces,
|
Iterators.Interfaces,
|
||||||
XMLSerializer.Interfaces,
|
XMLSerializer.Interfaces,
|
||||||
});
|
}){};
|
||||||
|
|
||||||
pub const UserContext = @import("user_context.zig").UserContext;
|
pub const UserContext = @import("user_context.zig").UserContext;
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ const std = @import("std");
|
|||||||
const jsruntime = @import("jsruntime");
|
const jsruntime = @import("jsruntime");
|
||||||
const Case = jsruntime.test_utils.Case;
|
const Case = jsruntime.test_utils.Case;
|
||||||
const checkCases = jsruntime.test_utils.checkCases;
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
const generate = @import("../generate.zig");
|
|
||||||
|
|
||||||
const parser = @import("netsurf");
|
const parser = @import("netsurf");
|
||||||
|
|
||||||
@@ -32,12 +31,12 @@ const ProcessingInstruction = @import("processing_instruction.zig").ProcessingIn
|
|||||||
const HTMLElem = @import("../html/elements.zig");
|
const HTMLElem = @import("../html/elements.zig");
|
||||||
|
|
||||||
// CharacterData interfaces
|
// CharacterData interfaces
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = .{
|
||||||
Comment,
|
Comment,
|
||||||
Text.Text,
|
Text.Text,
|
||||||
Text.Interfaces,
|
Text.Interfaces,
|
||||||
ProcessingInstruction,
|
ProcessingInstruction,
|
||||||
});
|
};
|
||||||
|
|
||||||
// CharacterData implementation
|
// CharacterData implementation
|
||||||
pub const CharacterData = struct {
|
pub const CharacterData = struct {
|
||||||
|
|||||||
@@ -16,8 +16,6 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
const generate = @import("../generate.zig");
|
|
||||||
|
|
||||||
const DOMException = @import("exceptions.zig").DOMException;
|
const DOMException = @import("exceptions.zig").DOMException;
|
||||||
const EventTarget = @import("event_target.zig").EventTarget;
|
const EventTarget = @import("event_target.zig").EventTarget;
|
||||||
const DOMImplementation = @import("implementation.zig").DOMImplementation;
|
const DOMImplementation = @import("implementation.zig").DOMImplementation;
|
||||||
@@ -27,7 +25,7 @@ const NodeList = @import("nodelist.zig");
|
|||||||
const Nod = @import("node.zig");
|
const Nod = @import("node.zig");
|
||||||
const MutationObserver = @import("mutation_observer.zig");
|
const MutationObserver = @import("mutation_observer.zig");
|
||||||
|
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = .{
|
||||||
DOMException,
|
DOMException,
|
||||||
EventTarget,
|
EventTarget,
|
||||||
DOMImplementation,
|
DOMImplementation,
|
||||||
@@ -37,4 +35,4 @@ pub const Interfaces = generate.Tuple(.{
|
|||||||
Nod.Node,
|
Nod.Node,
|
||||||
Nod.Interfaces,
|
Nod.Interfaces,
|
||||||
MutationObserver.Interfaces,
|
MutationObserver.Interfaces,
|
||||||
});
|
};
|
||||||
|
|||||||
@@ -26,15 +26,13 @@ const CallbackResult = jsruntime.CallbackResult;
|
|||||||
const Case = jsruntime.test_utils.Case;
|
const Case = jsruntime.test_utils.Case;
|
||||||
const checkCases = jsruntime.test_utils.checkCases;
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
|
|
||||||
const generate = @import("../generate.zig");
|
|
||||||
|
|
||||||
const NodeList = @import("nodelist.zig").NodeList;
|
const NodeList = @import("nodelist.zig").NodeList;
|
||||||
|
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = .{
|
||||||
MutationObserver,
|
MutationObserver,
|
||||||
MutationRecord,
|
MutationRecord,
|
||||||
MutationRecords,
|
MutationRecords,
|
||||||
});
|
};
|
||||||
|
|
||||||
const Walker = @import("../dom/walker.zig").WalkerChildren;
|
const Walker = @import("../dom/walker.zig").WalkerChildren;
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const HTML = @import("../html/html.zig");
|
|||||||
const HTMLElem = @import("../html/elements.zig");
|
const HTMLElem = @import("../html/elements.zig");
|
||||||
|
|
||||||
// Node interfaces
|
// Node interfaces
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = .{
|
||||||
Attr,
|
Attr,
|
||||||
CData.CharacterData,
|
CData.CharacterData,
|
||||||
CData.Interfaces,
|
CData.Interfaces,
|
||||||
@@ -57,12 +57,10 @@ pub const Interfaces = generate.Tuple(.{
|
|||||||
DocumentFragment,
|
DocumentFragment,
|
||||||
HTMLCollection,
|
HTMLCollection,
|
||||||
HTMLCollectionIterator,
|
HTMLCollectionIterator,
|
||||||
|
|
||||||
HTML.Interfaces,
|
HTML.Interfaces,
|
||||||
});
|
};
|
||||||
const Generated = generate.Union.compile(Interfaces);
|
|
||||||
pub const Union = Generated._union;
|
pub const Union = generate.Union(Interfaces);
|
||||||
pub const Tags = Generated._enum;
|
|
||||||
|
|
||||||
// Node implementation
|
// Node implementation
|
||||||
pub const Node = struct {
|
pub const Node = struct {
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ const Callback = jsruntime.Callback;
|
|||||||
const CallbackResult = jsruntime.CallbackResult;
|
const CallbackResult = jsruntime.CallbackResult;
|
||||||
const Case = jsruntime.test_utils.Case;
|
const Case = jsruntime.test_utils.Case;
|
||||||
const checkCases = jsruntime.test_utils.checkCases;
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
const generate = @import("../generate.zig");
|
|
||||||
|
|
||||||
const NodeUnion = @import("node.zig").Union;
|
const NodeUnion = @import("node.zig").Union;
|
||||||
const Node = @import("node.zig").Node;
|
const Node = @import("node.zig").Node;
|
||||||
@@ -36,10 +35,10 @@ const log = std.log.scoped(.nodelist);
|
|||||||
|
|
||||||
const DOMException = @import("exceptions.zig").DOMException;
|
const DOMException = @import("exceptions.zig").DOMException;
|
||||||
|
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = .{
|
||||||
NodeListIterator,
|
NodeListIterator,
|
||||||
NodeList,
|
NodeList,
|
||||||
});
|
};
|
||||||
|
|
||||||
pub const NodeListIterator = struct {
|
pub const NodeListIterator = struct {
|
||||||
pub const mem_guarantied = true;
|
pub const mem_guarantied = true;
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ const std = @import("std");
|
|||||||
const jsruntime = @import("jsruntime");
|
const jsruntime = @import("jsruntime");
|
||||||
const Case = jsruntime.test_utils.Case;
|
const Case = jsruntime.test_utils.Case;
|
||||||
const checkCases = jsruntime.test_utils.checkCases;
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
const generate = @import("../generate.zig");
|
|
||||||
|
|
||||||
const parser = @import("netsurf");
|
const parser = @import("netsurf");
|
||||||
|
|
||||||
@@ -31,9 +30,9 @@ const CDATASection = @import("cdata_section.zig").CDATASection;
|
|||||||
const UserContext = @import("../user_context.zig").UserContext;
|
const UserContext = @import("../user_context.zig").UserContext;
|
||||||
|
|
||||||
// Text interfaces
|
// Text interfaces
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = .{
|
||||||
CDATASection,
|
CDATASection,
|
||||||
});
|
};
|
||||||
|
|
||||||
pub const Text = struct {
|
pub const Text = struct {
|
||||||
pub const Self = parser.Text;
|
pub const Self = parser.Text;
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ const ProgressEvent = @import("../xhr/progress_event.zig").ProgressEvent;
|
|||||||
const log = std.log.scoped(.events);
|
const log = std.log.scoped(.events);
|
||||||
|
|
||||||
// Event interfaces
|
// Event interfaces
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = .{
|
||||||
Event,
|
Event,
|
||||||
ProgressEvent,
|
ProgressEvent,
|
||||||
});
|
};
|
||||||
const Generated = generate.Union.compile(Interfaces);
|
|
||||||
pub const Union = Generated._union;
|
pub const Union = generate.Union(Interfaces);
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#event
|
// https://dom.spec.whatwg.org/#event
|
||||||
pub const Event = struct {
|
pub const Event = struct {
|
||||||
|
|||||||
566
src/generate.zig
566
src/generate.zig
@@ -17,430 +17,202 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const Type = std.builtin.Type;
|
||||||
|
|
||||||
// Utils
|
pub fn Union(interfaces: anytype) type {
|
||||||
// -----
|
// @setEvalBranchQuota(10000);
|
||||||
|
const tuple = Tuple(interfaces){};
|
||||||
|
const fields = std.meta.fields(@TypeOf(tuple));
|
||||||
|
|
||||||
fn itoa(comptime i: u8) ![]const u8 {
|
const tag_type = switch (fields.len) {
|
||||||
var len: usize = undefined;
|
0 => unreachable,
|
||||||
if (i < 10) {
|
1 => u0,
|
||||||
len = 1;
|
2 => u1,
|
||||||
} else if (i < 100) {
|
3...4 => u2,
|
||||||
len = 2;
|
5...8 => u3,
|
||||||
} else if (i < 1000) {
|
9...16 => u4,
|
||||||
len = 3;
|
17...32 => u5,
|
||||||
} else {
|
33...64 => u6,
|
||||||
return error.GenerateTooMuchMembers;
|
65...128 => u7,
|
||||||
}
|
129...256 => u8,
|
||||||
var buf: [len]u8 = undefined;
|
else => @compileError("Too many interfaces to generate union"),
|
||||||
return try std.fmt.bufPrint(buf[0..], "{d}", .{i});
|
};
|
||||||
}
|
|
||||||
|
|
||||||
fn fmtName(comptime T: type) [:0]const u8 {
|
// second iteration to generate tags
|
||||||
var it = std.mem.splitBackwards(u8, @typeName(T), ".");
|
var enum_fields: [fields.len]Type.EnumField = undefined;
|
||||||
return it.first() ++ "";
|
for (fields, 0..) |field, index| {
|
||||||
}
|
const member = @field(tuple, field.name);
|
||||||
|
const full_name = @typeName(member);
|
||||||
// Union
|
const separator = std.mem.lastIndexOfScalar(u8, full_name, '.') orelse unreachable;
|
||||||
// -----
|
const name = full_name[separator + 1 ..];
|
||||||
|
enum_fields[index] = .{
|
||||||
// Generate a flatten tagged Union from various structs and union of structs
|
.name = name ++ "",
|
||||||
// TODO: make this function more generic
|
.value = index,
|
||||||
// TODO: dedup
|
|
||||||
pub const Union = struct {
|
|
||||||
_enum: type,
|
|
||||||
_union: type,
|
|
||||||
|
|
||||||
pub fn compile(comptime tuple: anytype) Union {
|
|
||||||
return private_compile(tuple) catch |err| @compileError(@errorName(err));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn private_compile(comptime tuple: anytype) !Union {
|
|
||||||
@setEvalBranchQuota(10000);
|
|
||||||
|
|
||||||
// check types provided
|
|
||||||
const tuple_T = @TypeOf(tuple);
|
|
||||||
const tuple_info = @typeInfo(tuple_T);
|
|
||||||
if (tuple_info != .Struct or !tuple_info.Struct.is_tuple) {
|
|
||||||
return error.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| {
|
|
||||||
const member_T = @field(tuple, member.name);
|
|
||||||
const member_info = @typeInfo(member_T);
|
|
||||||
if (member_info == .Union) {
|
|
||||||
const member_union = member_info.Union;
|
|
||||||
members_nb += member_union.fields.len;
|
|
||||||
} else if (member_info == .Struct) {
|
|
||||||
members_nb += 1;
|
|
||||||
} else {
|
|
||||||
return error.GenerateMemberNotUnionOrStruct;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// define the tag type regarding the members nb
|
|
||||||
var tag_type: type = undefined;
|
|
||||||
if (members_nb < 3) {
|
|
||||||
tag_type = u1;
|
|
||||||
} else if (members_nb < 4) {
|
|
||||||
tag_type = u2;
|
|
||||||
} else if (members_nb < 8) {
|
|
||||||
tag_type = u3;
|
|
||||||
} else if (members_nb < 16) {
|
|
||||||
tag_type = u4;
|
|
||||||
} else if (members_nb < 32) {
|
|
||||||
tag_type = u5;
|
|
||||||
} else if (members_nb < 64) {
|
|
||||||
tag_type = u6;
|
|
||||||
} else if (members_nb < 128) {
|
|
||||||
tag_type = u7;
|
|
||||||
} else if (members_nb < 256) {
|
|
||||||
tag_type = u8;
|
|
||||||
} else if (members_nb < 65536) {
|
|
||||||
tag_type = u16;
|
|
||||||
} else {
|
|
||||||
return error.GenerateTooMuchMembers;
|
|
||||||
}
|
|
||||||
|
|
||||||
// second iteration to generate tags
|
|
||||||
var enum_fields: [members_nb]std.builtin.Type.EnumField = undefined;
|
|
||||||
var done = 0;
|
|
||||||
for (tuple_members) |member| {
|
|
||||||
const member_T = @field(tuple, member.name);
|
|
||||||
const member_info = @typeInfo(member_T);
|
|
||||||
if (member_info == .Union) {
|
|
||||||
const member_union = member_info.Union;
|
|
||||||
for (member_union.fields) |field| {
|
|
||||||
enum_fields[done] = .{
|
|
||||||
.name = fmtName(field.type),
|
|
||||||
.value = done,
|
|
||||||
};
|
|
||||||
done += 1;
|
|
||||||
}
|
|
||||||
} else if (member_info == .Struct) {
|
|
||||||
enum_fields[done] = .{
|
|
||||||
.name = fmtName(member_T),
|
|
||||||
.value = done,
|
|
||||||
};
|
|
||||||
done += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const decls: [0]std.builtin.Type.Declaration = undefined;
|
|
||||||
const enum_info = std.builtin.Type.Enum{
|
|
||||||
.tag_type = tag_type,
|
|
||||||
.fields = &enum_fields,
|
|
||||||
.decls = &decls,
|
|
||||||
.is_exhaustive = true,
|
|
||||||
};
|
|
||||||
const enum_T = @Type(std.builtin.Type{ .Enum = enum_info });
|
|
||||||
|
|
||||||
// third iteration to generate union type
|
|
||||||
var union_fields: [members_nb]std.builtin.Type.UnionField = undefined;
|
|
||||||
done = 0;
|
|
||||||
for (tuple_members, 0..) |member, i| {
|
|
||||||
const member_T = @field(tuple, member.name);
|
|
||||||
const member_info = @typeInfo(member_T);
|
|
||||||
if (member_info == .Union) {
|
|
||||||
const member_union = member_info.Union;
|
|
||||||
for (member_union.fields) |field| {
|
|
||||||
var T: type = undefined;
|
|
||||||
if (@hasDecl(field.type, "Self")) {
|
|
||||||
T = @field(field.type, "Self");
|
|
||||||
T = *T;
|
|
||||||
} else {
|
|
||||||
T = field.type;
|
|
||||||
}
|
|
||||||
union_fields[done] = .{
|
|
||||||
.name = fmtName(field.type),
|
|
||||||
.type = T,
|
|
||||||
.alignment = @alignOf(T),
|
|
||||||
};
|
|
||||||
done += 1;
|
|
||||||
}
|
|
||||||
} else if (member_info == .Struct) {
|
|
||||||
const member_name = try itoa(i);
|
|
||||||
var T = @field(tuple, member_name);
|
|
||||||
if (@hasDecl(T, "Self")) {
|
|
||||||
T = @field(T, "Self");
|
|
||||||
T = *T;
|
|
||||||
}
|
|
||||||
union_fields[done] = .{
|
|
||||||
// UnionField.name expect a null terminated string.
|
|
||||||
// concatenate the `[]const u8` string with an empty string
|
|
||||||
// literal (`name ++ ""`) to explicitly coerce it to `[:0]const
|
|
||||||
// u8`.
|
|
||||||
.name = fmtName(member_T) ++ "",
|
|
||||||
.type = T,
|
|
||||||
.alignment = @alignOf(T),
|
|
||||||
};
|
|
||||||
done += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const union_info = std.builtin.Type.Union{
|
|
||||||
.layout = .auto,
|
|
||||||
.tag_type = enum_T,
|
|
||||||
.fields = &union_fields,
|
|
||||||
.decls = &decls,
|
|
||||||
};
|
|
||||||
const union_T = @Type(std.builtin.Type{ .Union = union_info });
|
|
||||||
|
|
||||||
return .{
|
|
||||||
._enum = enum_T,
|
|
||||||
._union = union_T,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Tuple
|
const enum_info = Type.Enum{
|
||||||
// -----
|
.tag_type = tag_type,
|
||||||
|
.fields = &enum_fields,
|
||||||
|
.decls = &.{},
|
||||||
|
.is_exhaustive = true,
|
||||||
|
};
|
||||||
|
const enum_T = @Type(std.builtin.Type{ .Enum = enum_info });
|
||||||
|
|
||||||
fn tupleNb(comptime tuple: anytype) usize {
|
// third iteration to generate union type
|
||||||
var nb = 0;
|
var union_fields: [fields.len]Type.UnionField = undefined;
|
||||||
for (@typeInfo(@TypeOf(tuple)).Struct.fields) |member| {
|
for (fields, enum_fields, 0..) |field, e, index| {
|
||||||
const member_T = @field(tuple, member.name);
|
var FT = @field(tuple, field.name);
|
||||||
if (@TypeOf(member_T) == type) {
|
if (@hasDecl(FT, "Self")) {
|
||||||
nb += 1;
|
FT = *(@field(FT, "Self"));
|
||||||
} else {
|
|
||||||
const member_info = @typeInfo(@TypeOf(member_T));
|
|
||||||
if (member_info != .Struct and !member_info.Struct.is_tuple) {
|
|
||||||
@compileError("GenerateMemberNotTypeOrTuple");
|
|
||||||
}
|
|
||||||
for (member_info.Struct.fields) |field| {
|
|
||||||
if (@TypeOf(@field(member_T, field.name)) != type) {
|
|
||||||
@compileError("GenerateMemberTupleChildNotType");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nb += member_info.Struct.fields.len;
|
|
||||||
}
|
}
|
||||||
|
union_fields[index] = .{
|
||||||
|
.type = FT,
|
||||||
|
.name = e.name,
|
||||||
|
.alignment = @alignOf(FT),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return nb;
|
|
||||||
|
return @Type(.{ .Union = .{
|
||||||
|
.layout = .auto,
|
||||||
|
.tag_type = enum_T,
|
||||||
|
.fields = &union_fields,
|
||||||
|
.decls = &.{},
|
||||||
|
} });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tupleTypes(comptime nb: usize, comptime tuple: anytype) [nb]type {
|
pub fn Tuple(args: anytype) type {
|
||||||
var types: [nb]type = undefined;
|
|
||||||
var done = 0;
|
|
||||||
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);
|
@setEvalBranchQuota(100000);
|
||||||
|
|
||||||
// logic
|
const count = countInterfaces(args, 0);
|
||||||
const nb = tupleNb(tuple);
|
var interfaces: [count]type = undefined;
|
||||||
const types = tupleTypes(nb, tuple);
|
_ = flattenInterfaces(args, &interfaces, 0);
|
||||||
const dedup_indexes = dedupIndexes(nb, types);
|
|
||||||
const dedup_nb = dedupNb(nb, dedup_indexes);
|
|
||||||
|
|
||||||
// generate the tuple type
|
const unfiltered_count, const filter_set = filterMap(count, interfaces);
|
||||||
var fields: [dedup_nb]std.builtin.Type.StructField = undefined;
|
|
||||||
var done = 0;
|
var field_index: usize = 0;
|
||||||
for (dedup_indexes) |index| {
|
var fields: [unfiltered_count]Type.StructField = undefined;
|
||||||
if (index == -1) {
|
|
||||||
|
for (filter_set, 0..) |filter, i| {
|
||||||
|
if (filter) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
fields[done] = .{
|
fields[field_index] = .{
|
||||||
// StructField.name expect a null terminated string.
|
.name = std.fmt.comptimePrint("{d}", .{field_index}),
|
||||||
// concatenate the `[]const u8` string with an empty string
|
|
||||||
// literal (`name ++ ""`) to explicitly coerce it to `[:0]const
|
|
||||||
// u8`.
|
|
||||||
.name = try itoa(done) ++ "",
|
|
||||||
.type = type,
|
.type = type,
|
||||||
.default_value = null,
|
// has to be true in order to properly capture the default value
|
||||||
.is_comptime = false,
|
.is_comptime = true,
|
||||||
.alignment = @alignOf(type),
|
.alignment = @alignOf(type),
|
||||||
|
.default_value = @ptrCast(&interfaces[i]),
|
||||||
};
|
};
|
||||||
done += 1;
|
field_index += 1;
|
||||||
}
|
}
|
||||||
const decls: [0]std.builtin.Type.Declaration = undefined;
|
|
||||||
const info = std.builtin.Type.Struct{
|
return @Type(.{ .Struct = .{
|
||||||
.layout = .auto,
|
.layout = .auto,
|
||||||
.fields = &fields,
|
.fields = &fields,
|
||||||
.decls = &decls,
|
.decls = &.{},
|
||||||
.is_tuple = true,
|
.is_tuple = true,
|
||||||
};
|
} });
|
||||||
return @Type(std.builtin.Type{ .Struct = info });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a flatten tuple from various structs and tuple of structs
|
fn countInterfaces(args: anytype, count: usize) usize {
|
||||||
// Duplicates will be removed.
|
var new_count = count;
|
||||||
// TODO: make this function more generic
|
for (@typeInfo(@TypeOf(args)).Struct.fields) |f| {
|
||||||
pub fn Tuple(comptime tuple: anytype) TupleT(tuple) {
|
const member = @field(args, f.name);
|
||||||
|
if (@TypeOf(member) == type) {
|
||||||
// check types provided
|
new_count += 1;
|
||||||
const tuple_T = @TypeOf(tuple);
|
} else {
|
||||||
const tuple_info = @typeInfo(tuple_T);
|
new_count = countInterfaces(member, new_count);
|
||||||
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 (dedup_indexes) |index| {
|
|
||||||
if (index == -1) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
const name = try itoa(done);
|
|
||||||
@field(t, name) = types[index];
|
|
||||||
done += 1;
|
|
||||||
}
|
}
|
||||||
return t;
|
return new_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests
|
fn flattenInterfaces(args: anytype, interfaces: []type, index: usize) usize {
|
||||||
// -----
|
var new_index = index;
|
||||||
|
for (@typeInfo(@TypeOf(args)).Struct.fields) |f| {
|
||||||
const Error = error{
|
const member = @field(args, f.name);
|
||||||
GenerateArgNotTuple,
|
if (@TypeOf(member) == type) {
|
||||||
GenerateMemberNotUnionOrStruct,
|
interfaces[new_index] = member;
|
||||||
GenerateMemberNotTupleOrStruct,
|
new_index += 1;
|
||||||
GenerateMemberTupleNotStruct,
|
} else {
|
||||||
GenerateTooMuchMembers,
|
new_index = flattenInterfaces(member, interfaces, new_index);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
const Astruct = struct {
|
return new_index;
|
||||||
value: u8 = 0,
|
}
|
||||||
};
|
|
||||||
const Bstruct = struct {
|
fn filterMap(comptime count: usize, interfaces: [count]type) struct { usize, [count]bool } {
|
||||||
value: u8 = 0,
|
var map: [count]bool = undefined;
|
||||||
};
|
var unfiltered_count: usize = 0;
|
||||||
const Cstruct = struct {
|
outer: for (interfaces, 0..) |iface, i| {
|
||||||
value: u8 = 0,
|
for (interfaces[i + 1 ..]) |check| {
|
||||||
};
|
if (iface == check) {
|
||||||
const Dstruct = struct {
|
map[i] = true;
|
||||||
value: u8 = 0,
|
continue :outer;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
pub fn tests() !void {
|
map[i] = false;
|
||||||
|
unfiltered_count += 1;
|
||||||
// Union from structs
|
}
|
||||||
const FromStructs = try Union.private_compile(.{ Astruct, Bstruct, Cstruct });
|
return .{ unfiltered_count, map };
|
||||||
|
}
|
||||||
const from_structs_enum = @typeInfo(FromStructs._enum);
|
|
||||||
try std.testing.expect(from_structs_enum == .Enum);
|
test "generate.Union" {
|
||||||
try std.testing.expect(from_structs_enum.Enum.fields.len == 3);
|
const Astruct = struct {
|
||||||
try std.testing.expect(from_structs_enum.Enum.tag_type == u2);
|
pub const Self = Other;
|
||||||
try std.testing.expect(from_structs_enum.Enum.fields[0].value == 0);
|
const Other = struct {};
|
||||||
try std.testing.expectEqualStrings(from_structs_enum.Enum.fields[0].name, "Astruct");
|
};
|
||||||
|
|
||||||
const from_structs_union = @typeInfo(FromStructs._union);
|
const Bstruct = struct {
|
||||||
try std.testing.expect(from_structs_union == .Union);
|
value: u8 = 0,
|
||||||
try std.testing.expect(from_structs_union.Union.tag_type == FromStructs._enum);
|
};
|
||||||
try std.testing.expect(from_structs_union.Union.fields.len == 3);
|
|
||||||
try std.testing.expect(from_structs_union.Union.fields[0].type == Astruct);
|
const Cstruct = struct {
|
||||||
try std.testing.expectEqualStrings(from_structs_union.Union.fields[0].name, "Astruct");
|
value: u8 = 0,
|
||||||
|
};
|
||||||
// Union from union and structs
|
|
||||||
const FromMix = try Union.private_compile(.{ FromStructs._union, Dstruct });
|
const value = Union(.{ Astruct, Bstruct, .{ Cstruct } });
|
||||||
|
const ti = @typeInfo(value).Union;
|
||||||
const from_mix_enum = @typeInfo(FromMix._enum);
|
try std.testing.expectEqual(3, ti.fields.len);
|
||||||
try std.testing.expect(from_mix_enum == .Enum);
|
try std.testing.expectEqualStrings("*generate.test.generate.Union.Astruct.Other", @typeName(ti.fields[0].type));
|
||||||
try std.testing.expect(from_mix_enum.Enum.fields.len == 4);
|
try std.testing.expectEqualStrings(ti.fields[0].name, "Astruct");
|
||||||
try std.testing.expect(from_mix_enum.Enum.tag_type == u3);
|
try std.testing.expectEqual(Bstruct, ti.fields[1].type);
|
||||||
try std.testing.expect(from_mix_enum.Enum.fields[0].value == 0);
|
try std.testing.expectEqualStrings(ti.fields[1].name, "Bstruct");
|
||||||
try std.testing.expectEqualStrings(from_mix_enum.Enum.fields[3].name, "Dstruct");
|
try std.testing.expectEqual(Cstruct, ti.fields[2].type);
|
||||||
|
try std.testing.expectEqualStrings(ti.fields[2].name, "Cstruct");
|
||||||
const from_mix_union = @typeInfo(FromMix._union);
|
}
|
||||||
try std.testing.expect(from_mix_union == .Union);
|
|
||||||
try std.testing.expect(from_mix_union.Union.tag_type == FromMix._enum);
|
test "generate.Tuple" {
|
||||||
try std.testing.expect(from_mix_union.Union.fields.len == 4);
|
const Astruct = struct {
|
||||||
try std.testing.expect(from_mix_union.Union.fields[3].type == Dstruct);
|
};
|
||||||
try std.testing.expectEqualStrings(from_mix_union.Union.fields[3].name, "Dstruct");
|
|
||||||
|
const Bstruct = struct {
|
||||||
std.debug.print("Generate Union: OK\n", .{});
|
value: u8 = 0,
|
||||||
|
};
|
||||||
// Tuple from structs
|
|
||||||
const tuple_structs = .{ Astruct, Bstruct };
|
const Cstruct = struct {
|
||||||
const tFromStructs = Tuple(tuple_structs);
|
value: u8 = 0,
|
||||||
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);
|
{
|
||||||
try std.testing.expect(t_from_structs.Struct.fields.len == 2);
|
const tuple = Tuple(.{ Astruct, Bstruct }){};
|
||||||
try std.testing.expect(@field(tFromStructs, "0") == Astruct);
|
const ti = @typeInfo(@TypeOf(tuple)).Struct;
|
||||||
try std.testing.expect(@field(tFromStructs, "1") == Bstruct);
|
try std.testing.expectEqual(true, ti.is_tuple);
|
||||||
|
try std.testing.expectEqual(2, ti.fields.len);
|
||||||
// Tuple from tuple and structs
|
try std.testing.expectEqual(Astruct, tuple.@"0");
|
||||||
const tuple_mix = .{ tFromStructs, Cstruct };
|
try std.testing.expectEqual(Bstruct, tuple.@"1");
|
||||||
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);
|
// dedupe
|
||||||
try std.testing.expect(t_from_mix.Struct.fields.len == 3);
|
const tuple = Tuple(.{ Cstruct, Astruct, .{ Astruct }, Bstruct, .{ Astruct, .{ Astruct, Bstruct } } }){};
|
||||||
try std.testing.expect(@field(tFromMix, "0") == Astruct);
|
const ti = @typeInfo(@TypeOf(tuple)).Struct;
|
||||||
try std.testing.expect(@field(tFromMix, "1") == Bstruct);
|
try std.testing.expectEqual(true, ti.is_tuple);
|
||||||
try std.testing.expect(@field(tFromMix, "2") == Cstruct);
|
try std.testing.expectEqual(3, ti.fields.len);
|
||||||
|
try std.testing.expectEqual(Cstruct, tuple.@"0");
|
||||||
// Tuple with dedup
|
try std.testing.expectEqual(Astruct, tuple.@"1");
|
||||||
const tuple_dedup = .{ Cstruct, Astruct, tFromStructs, Bstruct };
|
try std.testing.expectEqual(Bstruct, tuple.@"2");
|
||||||
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", .{});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,9 +99,8 @@ pub const Interfaces = .{
|
|||||||
HTMLVideoElement,
|
HTMLVideoElement,
|
||||||
CSSProperties,
|
CSSProperties,
|
||||||
};
|
};
|
||||||
const Generated = generate.Union.compile(Interfaces);
|
|
||||||
pub const Union = Generated._union;
|
pub const Union = generate.Union(Interfaces);
|
||||||
pub const Tags = Generated._enum;
|
|
||||||
|
|
||||||
// Abstract class
|
// Abstract class
|
||||||
// --------------
|
// --------------
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const Navigator = @import("navigator.zig").Navigator;
|
|||||||
const History = @import("history.zig").History;
|
const History = @import("history.zig").History;
|
||||||
const Location = @import("location.zig").Location;
|
const Location = @import("location.zig").Location;
|
||||||
|
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = .{
|
||||||
HTMLDocument,
|
HTMLDocument,
|
||||||
HTMLElem.HTMLElement,
|
HTMLElem.HTMLElement,
|
||||||
HTMLElem.HTMLMediaElement,
|
HTMLElem.HTMLMediaElement,
|
||||||
@@ -34,4 +34,4 @@ pub const Interfaces = generate.Tuple(.{
|
|||||||
Navigator,
|
Navigator,
|
||||||
History,
|
History,
|
||||||
Location,
|
Location,
|
||||||
});
|
};
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const generate = @import("../generate.zig");
|
pub const Interfaces = .{
|
||||||
|
|
||||||
pub const Interfaces = generate.Tuple(.{
|
|
||||||
U32Iterator,
|
U32Iterator,
|
||||||
});
|
};
|
||||||
|
|
||||||
pub const U32Iterator = struct {
|
pub const U32Iterator = struct {
|
||||||
pub const mem_guarantied = true;
|
pub const mem_guarantied = true;
|
||||||
|
|||||||
@@ -332,13 +332,11 @@ test {
|
|||||||
const queryTest = @import("url/query.zig");
|
const queryTest = @import("url/query.zig");
|
||||||
std.testing.refAllDecls(queryTest);
|
std.testing.refAllDecls(queryTest);
|
||||||
|
|
||||||
|
std.testing.refAllDecls(@import("generate.zig"));
|
||||||
std.testing.refAllDecls(@import("cdp/msg.zig"));
|
std.testing.refAllDecls(@import("cdp/msg.zig"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testJSRuntime(alloc: std.mem.Allocator) !void {
|
fn testJSRuntime(alloc: std.mem.Allocator) !void {
|
||||||
// generate tests
|
|
||||||
try generate.tests();
|
|
||||||
|
|
||||||
// create JS vm
|
// create JS vm
|
||||||
const vm = jsruntime.VM.init();
|
const vm = jsruntime.VM.init();
|
||||||
defer vm.deinit();
|
defer vm.deinit();
|
||||||
|
|||||||
@@ -21,15 +21,13 @@ const std = @import("std");
|
|||||||
const jsruntime = @import("jsruntime");
|
const jsruntime = @import("jsruntime");
|
||||||
const Case = jsruntime.test_utils.Case;
|
const Case = jsruntime.test_utils.Case;
|
||||||
const checkCases = jsruntime.test_utils.checkCases;
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
const generate = @import("../generate.zig");
|
|
||||||
|
|
||||||
const DOMError = @import("netsurf").DOMError;
|
const DOMError = @import("netsurf").DOMError;
|
||||||
|
|
||||||
const log = std.log.scoped(.storage);
|
const log = std.log.scoped(.storage);
|
||||||
|
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = .{
|
||||||
Bottle,
|
Bottle,
|
||||||
});
|
};
|
||||||
|
|
||||||
// See https://storage.spec.whatwg.org/#model for storage hierarchy.
|
// See https://storage.spec.whatwg.org/#model for storage hierarchy.
|
||||||
// A Shed contains map of Shelves. The key is the document's origin.
|
// A Shed contains map of Shelves. The key is the document's origin.
|
||||||
|
|||||||
@@ -21,14 +21,13 @@ const std = @import("std");
|
|||||||
const jsruntime = @import("jsruntime");
|
const jsruntime = @import("jsruntime");
|
||||||
const Case = jsruntime.test_utils.Case;
|
const Case = jsruntime.test_utils.Case;
|
||||||
const checkCases = jsruntime.test_utils.checkCases;
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
const generate = @import("../generate.zig");
|
|
||||||
|
|
||||||
const query = @import("query.zig");
|
const query = @import("query.zig");
|
||||||
|
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = .{
|
||||||
URL,
|
URL,
|
||||||
URLSearchParams,
|
URLSearchParams,
|
||||||
});
|
};
|
||||||
|
|
||||||
// https://url.spec.whatwg.org/#url
|
// https://url.spec.whatwg.org/#url
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ const std = @import("std");
|
|||||||
const jsruntime = @import("jsruntime");
|
const jsruntime = @import("jsruntime");
|
||||||
const Case = jsruntime.test_utils.Case;
|
const Case = jsruntime.test_utils.Case;
|
||||||
const checkCases = jsruntime.test_utils.checkCases;
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
const generate = @import("../generate.zig");
|
|
||||||
|
|
||||||
const DOMError = @import("netsurf").DOMError;
|
const DOMError = @import("netsurf").DOMError;
|
||||||
const DOMException = @import("../dom/exceptions.zig").DOMException;
|
const DOMException = @import("../dom/exceptions.zig").DOMException;
|
||||||
@@ -42,11 +41,11 @@ const log = std.log.scoped(.xhr);
|
|||||||
|
|
||||||
// XHR interfaces
|
// XHR interfaces
|
||||||
// https://xhr.spec.whatwg.org/#interface-xmlhttprequest
|
// https://xhr.spec.whatwg.org/#interface-xmlhttprequest
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = .{
|
||||||
XMLHttpRequestEventTarget,
|
XMLHttpRequestEventTarget,
|
||||||
XMLHttpRequestUpload,
|
XMLHttpRequestUpload,
|
||||||
XMLHttpRequest,
|
XMLHttpRequest,
|
||||||
});
|
};
|
||||||
|
|
||||||
pub const XMLHttpRequestUpload = struct {
|
pub const XMLHttpRequestUpload = struct {
|
||||||
pub const prototype = *XMLHttpRequestEventTarget;
|
pub const prototype = *XMLHttpRequestEventTarget;
|
||||||
|
|||||||
@@ -21,16 +21,15 @@ const std = @import("std");
|
|||||||
const jsruntime = @import("jsruntime");
|
const jsruntime = @import("jsruntime");
|
||||||
const Case = jsruntime.test_utils.Case;
|
const Case = jsruntime.test_utils.Case;
|
||||||
const checkCases = jsruntime.test_utils.checkCases;
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
const generate = @import("../generate.zig");
|
|
||||||
|
|
||||||
const DOMError = @import("netsurf").DOMError;
|
const DOMError = @import("netsurf").DOMError;
|
||||||
|
|
||||||
const parser = @import("netsurf");
|
const parser = @import("netsurf");
|
||||||
const dump = @import("../browser/dump.zig");
|
const dump = @import("../browser/dump.zig");
|
||||||
|
|
||||||
pub const Interfaces = generate.Tuple(.{
|
pub const Interfaces = .{
|
||||||
XMLSerializer,
|
XMLSerializer,
|
||||||
});
|
};
|
||||||
|
|
||||||
// https://w3c.github.io/DOM-Parsing/#dom-xmlserializer-constructor
|
// https://w3c.github.io/DOM-Parsing/#dom-xmlserializer-constructor
|
||||||
pub const XMLSerializer = struct {
|
pub const XMLSerializer = struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user