mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
69
src/dom.zig
69
src/dom.zig
@@ -1,3 +1,5 @@
|
|||||||
|
const generate = @import("generate.zig");
|
||||||
|
|
||||||
const Console = @import("jsruntime").Console;
|
const Console = @import("jsruntime").Console;
|
||||||
|
|
||||||
// DOM
|
// DOM
|
||||||
@@ -12,7 +14,7 @@ pub const HTMLDocument = @import("html/document.zig").HTMLDocument;
|
|||||||
const E = @import("html/elements.zig");
|
const E = @import("html/elements.zig");
|
||||||
|
|
||||||
// Interfaces
|
// Interfaces
|
||||||
pub const Interfaces = .{
|
const interfaces = .{
|
||||||
Console,
|
Console,
|
||||||
|
|
||||||
// DOM
|
// DOM
|
||||||
@@ -23,69 +25,8 @@ pub const Interfaces = .{
|
|||||||
|
|
||||||
// HTML
|
// HTML
|
||||||
HTMLDocument,
|
HTMLDocument,
|
||||||
|
|
||||||
E.HTMLElement,
|
E.HTMLElement,
|
||||||
E.HTMLMediaElement,
|
E.HTMLMediaElement,
|
||||||
|
E.HTMLElementsTypes,
|
||||||
// TODO: generate HTMLElements comptime
|
|
||||||
E.HTMLUnknownElement,
|
|
||||||
E.HTMLAnchorElement,
|
|
||||||
E.HTMLAreaElement,
|
|
||||||
E.HTMLAudioElement,
|
|
||||||
E.HTMLBRElement,
|
|
||||||
E.HTMLBaseElement,
|
|
||||||
E.HTMLBodyElement,
|
|
||||||
E.HTMLButtonElement,
|
|
||||||
E.HTMLCanvasElement,
|
|
||||||
E.HTMLDListElement,
|
|
||||||
E.HTMLDialogElement,
|
|
||||||
E.HTMLDataElement,
|
|
||||||
E.HTMLDivElement,
|
|
||||||
E.HTMLEmbedElement,
|
|
||||||
E.HTMLFieldSetElement,
|
|
||||||
E.HTMLFormElement,
|
|
||||||
E.HTMLFrameSetElement,
|
|
||||||
E.HTMLHRElement,
|
|
||||||
E.HTMLHeadElement,
|
|
||||||
E.HTMLHeadingElement,
|
|
||||||
E.HTMLHtmlElement,
|
|
||||||
E.HTMLIFrameElement,
|
|
||||||
E.HTMLImageElement,
|
|
||||||
E.HTMLInputElement,
|
|
||||||
E.HTMLLIElement,
|
|
||||||
E.HTMLLabelElement,
|
|
||||||
E.HTMLLegendElement,
|
|
||||||
E.HTMLLinkElement,
|
|
||||||
E.HTMLMapElement,
|
|
||||||
E.HTMLMetaElement,
|
|
||||||
E.HTMLMeterElement,
|
|
||||||
E.HTMLModElement,
|
|
||||||
E.HTMLOListElement,
|
|
||||||
E.HTMLObjectElement,
|
|
||||||
E.HTMLOptGroupElement,
|
|
||||||
E.HTMLOptionElement,
|
|
||||||
E.HTMLOutputElement,
|
|
||||||
E.HTMLParagraphElement,
|
|
||||||
E.HTMLPictureElement,
|
|
||||||
E.HTMLPreElement,
|
|
||||||
E.HTMLProgressElement,
|
|
||||||
E.HTMLQuoteElement,
|
|
||||||
E.HTMLScriptElement,
|
|
||||||
E.HTMLSelectElement,
|
|
||||||
E.HTMLSourceElement,
|
|
||||||
E.HTMLSpanElement,
|
|
||||||
E.HTMLStyleElement,
|
|
||||||
E.HTMLTableElement,
|
|
||||||
E.HTMLTableCaptionElement,
|
|
||||||
E.HTMLTableCellElement,
|
|
||||||
E.HTMLTableColElement,
|
|
||||||
E.HTMLTableRowElement,
|
|
||||||
E.HTMLTableSectionElement,
|
|
||||||
E.HTMLTemplateElement,
|
|
||||||
E.HTMLTextAreaElement,
|
|
||||||
E.HTMLTimeElement,
|
|
||||||
E.HTMLTitleElement,
|
|
||||||
E.HTMLTrackElement,
|
|
||||||
E.HTMLUListElement,
|
|
||||||
E.HTMLVideoElement,
|
|
||||||
};
|
};
|
||||||
|
pub const Interfaces = generate.TupleInst(generate.TupleT(interfaces), interfaces);
|
||||||
|
|||||||
334
src/generate.zig
Normal file
334
src/generate.zig
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
|
fn fmtName(comptime T: type) []const u8 {
|
||||||
|
var it = std.mem.splitBackwards(u8, @typeName(T), ".");
|
||||||
|
return it.first();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a flatten tagged Union from various structs and union of structs
|
||||||
|
// TODO: make this function more generic
|
||||||
|
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 = u4;
|
||||||
|
} 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.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{
|
||||||
|
.layout = .Auto,
|
||||||
|
.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) |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| {
|
||||||
|
union_fields[done] = .{
|
||||||
|
.name = fmtName(field.field_type),
|
||||||
|
.field_type = field.field_type,
|
||||||
|
.alignment = field.alignment,
|
||||||
|
};
|
||||||
|
done += 1;
|
||||||
|
}
|
||||||
|
} else if (member_info == .Struct) {
|
||||||
|
const alignment = tuple_info.Struct.fields[i].alignment;
|
||||||
|
union_fields[done] = .{
|
||||||
|
.name = fmtName(member_T),
|
||||||
|
.field_type = member_T,
|
||||||
|
.alignment = alignment,
|
||||||
|
};
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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| {
|
||||||
|
const member_T = @field(tuple, member.name);
|
||||||
|
if (@TypeOf(member_T) == type) {
|
||||||
|
members_nb += 1;
|
||||||
|
} 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
members_nb += member_info.Struct.fields.len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// second iteration to generate the tuple type
|
||||||
|
var fields: [members_nb]std.builtin.Type.StructField = undefined;
|
||||||
|
var done = 0;
|
||||||
|
while (done < members_nb) {
|
||||||
|
fields[done] = .{
|
||||||
|
.name = try itoa(done),
|
||||||
|
.field_type = type,
|
||||||
|
.default_value = null,
|
||||||
|
.is_comptime = false,
|
||||||
|
.alignment = @alignOf(type),
|
||||||
|
};
|
||||||
|
done += 1;
|
||||||
|
}
|
||||||
|
const decls: [0]std.builtin.Type.Declaration = undefined;
|
||||||
|
const info = std.builtin.Type.Struct{
|
||||||
|
.layout = .Auto,
|
||||||
|
.fields = &fields,
|
||||||
|
.decls = &decls,
|
||||||
|
.is_tuple = true,
|
||||||
|
};
|
||||||
|
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
|
||||||
|
// TODO: make this function more generic
|
||||||
|
pub fn TupleInst(comptime T: type, comptime tuple: anytype) T {
|
||||||
|
|
||||||
|
// check types provided
|
||||||
|
const tuple_T = @TypeOf(tuple);
|
||||||
|
const tuple_info = @typeInfo(tuple_T);
|
||||||
|
const tuple_members = tuple_info.Struct.fields;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
// -----
|
||||||
|
|
||||||
|
const Error = error{
|
||||||
|
GenerateArgNotTuple,
|
||||||
|
GenerateMemberNotUnionOrStruct,
|
||||||
|
GenerateMemberNotTupleOrStruct,
|
||||||
|
GenerateMemberTupleNotStruct,
|
||||||
|
GenerateTooMuchMembers,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Astruct = struct {
|
||||||
|
value: u8 = 0,
|
||||||
|
};
|
||||||
|
const Bstruct = struct {
|
||||||
|
value: u8 = 0,
|
||||||
|
};
|
||||||
|
const Cstruct = struct {
|
||||||
|
value: u8 = 0,
|
||||||
|
};
|
||||||
|
const Dstruct = struct {
|
||||||
|
value: u8 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn tests() !void {
|
||||||
|
|
||||||
|
// Union from structs
|
||||||
|
const FromStructs = try Union.private_compile(.{ Astruct, Bstruct, Cstruct });
|
||||||
|
|
||||||
|
const from_structs_enum = @typeInfo(FromStructs._enum);
|
||||||
|
try std.testing.expect(from_structs_enum == .Enum);
|
||||||
|
try std.testing.expect(from_structs_enum.Enum.fields.len == 3);
|
||||||
|
try std.testing.expect(from_structs_enum.Enum.tag_type == u2);
|
||||||
|
try std.testing.expect(from_structs_enum.Enum.fields[0].value == 0);
|
||||||
|
try std.testing.expectEqualStrings(from_structs_enum.Enum.fields[0].name, "Astruct");
|
||||||
|
|
||||||
|
const from_structs_union = @typeInfo(FromStructs._union);
|
||||||
|
try std.testing.expect(from_structs_union == .Union);
|
||||||
|
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].field_type == Astruct);
|
||||||
|
try std.testing.expectEqualStrings(from_structs_union.Union.fields[0].name, "Astruct");
|
||||||
|
|
||||||
|
// Union from union and structs
|
||||||
|
const FromMix = try Union.private_compile(.{ FromStructs._union, Dstruct });
|
||||||
|
|
||||||
|
const from_mix_enum = @typeInfo(FromMix._enum);
|
||||||
|
try std.testing.expect(from_mix_enum == .Enum);
|
||||||
|
try std.testing.expect(from_mix_enum.Enum.fields.len == 4);
|
||||||
|
try std.testing.expect(from_mix_enum.Enum.tag_type == u3);
|
||||||
|
try std.testing.expect(from_mix_enum.Enum.fields[0].value == 0);
|
||||||
|
try std.testing.expectEqualStrings(from_mix_enum.Enum.fields[3].name, "Dstruct");
|
||||||
|
|
||||||
|
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);
|
||||||
|
try std.testing.expect(from_mix_union.Union.fields.len == 4);
|
||||||
|
try std.testing.expect(from_mix_union.Union.fields[3].field_type == Dstruct);
|
||||||
|
try std.testing.expectEqualStrings(from_mix_union.Union.fields[3].name, "Dstruct");
|
||||||
|
|
||||||
|
std.debug.print("Generate Union: OK\n", .{});
|
||||||
|
|
||||||
|
// Tuple from structs
|
||||||
|
const tuple_structs = .{ Astruct, Bstruct };
|
||||||
|
const tFromStructs = TupleInst(TupleT(tuple_structs), 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);
|
||||||
|
try std.testing.expect(t_from_structs.Struct.fields.len == 2);
|
||||||
|
try std.testing.expect(@field(tFromStructs, "0") == Astruct);
|
||||||
|
try std.testing.expect(@field(tFromStructs, "1") == Bstruct);
|
||||||
|
|
||||||
|
// Tuple from tuple and structs
|
||||||
|
const tuple_mix = .{ tFromStructs, Cstruct };
|
||||||
|
const tFromMix = TupleInst(TupleT(tuple_mix), 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);
|
||||||
|
try std.testing.expect(t_from_mix.Struct.fields.len == 3);
|
||||||
|
try std.testing.expect(@field(tFromMix, "0") == Astruct);
|
||||||
|
try std.testing.expect(@field(tFromMix, "1") == Bstruct);
|
||||||
|
try std.testing.expect(@field(tFromMix, "2") == Cstruct);
|
||||||
|
|
||||||
|
std.debug.print("Generate Tuple: OK\n", .{});
|
||||||
|
}
|
||||||
@@ -50,187 +50,13 @@ pub const HTMLDocument = struct {
|
|||||||
|
|
||||||
pub fn _createElement(self: HTMLDocument, tag_name: []const u8) E.HTMLElements {
|
pub fn _createElement(self: HTMLDocument, tag_name: []const u8) E.HTMLElements {
|
||||||
const base = parser.documentCreateElement(self.proto.base.?, tag_name);
|
const base = parser.documentCreateElement(self.proto.base.?, tag_name);
|
||||||
|
return E.ElementToHTMLElementInterface(base);
|
||||||
// TODO: order by probability instead of alphabetically
|
|
||||||
// TODO: this does not seems very efficient, do we have a better way?
|
|
||||||
if (std.mem.eql(u8, tag_name, "a")) {
|
|
||||||
return .{ .anchor = E.HTMLAnchorElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "area")) {
|
|
||||||
return .{ .area = E.HTMLAreaElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "audio")) {
|
|
||||||
return .{ .audio = E.HTMLAudioElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "br")) {
|
|
||||||
return .{ .br = E.HTMLBRElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "base")) {
|
|
||||||
return .{ .base = E.HTMLBaseElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "body")) {
|
|
||||||
return .{ .body = E.HTMLBodyElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "button")) {
|
|
||||||
return .{ .button = E.HTMLButtonElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "canvas")) {
|
|
||||||
return .{ .canvas = E.HTMLCanvasElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "dl")) {
|
|
||||||
return .{ .dlist = E.HTMLDListElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "dialog")) {
|
|
||||||
return .{ .dialog = E.HTMLDialogElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "data")) {
|
|
||||||
return .{ .data = E.HTMLDataElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "div")) {
|
|
||||||
return .{ .div = E.HTMLDivElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "embed")) {
|
|
||||||
return .{ .embed = E.HTMLEmbedElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "fieldset")) {
|
|
||||||
return .{ .fieldset = E.HTMLFieldSetElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "form")) {
|
|
||||||
return .{ .form = E.HTMLFormElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "frameset")) {
|
|
||||||
return .{ .frameset = E.HTMLFrameSetElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "hr")) {
|
|
||||||
return .{ .hr = E.HTMLHRElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "head")) {
|
|
||||||
return .{ .head = E.HTMLHeadElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "h1")) {
|
|
||||||
return .{ .heading = E.HTMLHeadingElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "h2")) {
|
|
||||||
return .{ .heading = E.HTMLHeadingElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "h3")) {
|
|
||||||
return .{ .heading = E.HTMLHeadingElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "h4")) {
|
|
||||||
return .{ .heading = E.HTMLHeadingElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "h5")) {
|
|
||||||
return .{ .heading = E.HTMLHeadingElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "h6")) {
|
|
||||||
return .{ .heading = E.HTMLHeadingElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "html")) {
|
|
||||||
return .{ .html = E.HTMLHtmlElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "iframe")) {
|
|
||||||
return .{ .iframe = E.HTMLIFrameElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "img")) {
|
|
||||||
return .{ .img = E.HTMLImageElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "input")) {
|
|
||||||
return .{ .input = E.HTMLInputElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "li")) {
|
|
||||||
return .{ .li = E.HTMLLIElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "label")) {
|
|
||||||
return .{ .label = E.HTMLLabelElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "legend")) {
|
|
||||||
return .{ .legend = E.HTMLLegendElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "link")) {
|
|
||||||
return .{ .link = E.HTMLLinkElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "map")) {
|
|
||||||
return .{ .map = E.HTMLMapElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "meta")) {
|
|
||||||
return .{ .meta = E.HTMLMetaElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "meter")) {
|
|
||||||
return .{ .meter = E.HTMLMeterElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "ins")) {
|
|
||||||
return .{ .mod = E.HTMLModElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "del")) {
|
|
||||||
return .{ .mod = E.HTMLModElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "ol")) {
|
|
||||||
return .{ .olist = E.HTMLOListElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "object")) {
|
|
||||||
return .{ .object = E.HTMLObjectElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "optgroup")) {
|
|
||||||
return .{ .optgroup = E.HTMLOptGroupElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "option")) {
|
|
||||||
return .{ .option = E.HTMLOptionElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "output")) {
|
|
||||||
return .{ .output = E.HTMLOutputElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "p")) {
|
|
||||||
return .{ .paragraph = E.HTMLParagraphElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "picture")) {
|
|
||||||
return .{ .picture = E.HTMLPictureElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "pre")) {
|
|
||||||
return .{ .pre = E.HTMLPreElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "progress")) {
|
|
||||||
return .{ .progress = E.HTMLProgressElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "blockquote")) {
|
|
||||||
return .{ .quote = E.HTMLQuoteElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "q")) {
|
|
||||||
return .{ .quote = E.HTMLQuoteElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "script")) {
|
|
||||||
return .{ .script = E.HTMLScriptElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "select")) {
|
|
||||||
return .{ .select = E.HTMLSelectElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "source")) {
|
|
||||||
return .{ .source = E.HTMLSourceElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "span")) {
|
|
||||||
return .{ .span = E.HTMLSpanElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "style")) {
|
|
||||||
return .{ .style = E.HTMLStyleElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "table")) {
|
|
||||||
return .{ .table = E.HTMLTableElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "caption")) {
|
|
||||||
return .{ .tablecaption = E.HTMLTableCaptionElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "th")) {
|
|
||||||
return .{ .tablecell = E.HTMLTableCellElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "td")) {
|
|
||||||
return .{ .tablecell = E.HTMLTableCellElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "col")) {
|
|
||||||
return .{ .tablecol = E.HTMLTableColElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "tr")) {
|
|
||||||
return .{ .tablerow = E.HTMLTableRowElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "thead")) {
|
|
||||||
return .{ .tablesection = E.HTMLTableSectionElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "tbody")) {
|
|
||||||
return .{ .tablesection = E.HTMLTableSectionElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "tfoot")) {
|
|
||||||
return .{ .tablesection = E.HTMLTableSectionElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "template")) {
|
|
||||||
return .{ .template = E.HTMLTemplateElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "textarea")) {
|
|
||||||
return .{ .textarea = E.HTMLTextAreaElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "time")) {
|
|
||||||
return .{ .time = E.HTMLTimeElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "title")) {
|
|
||||||
return .{ .title = E.HTMLTitleElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "track")) {
|
|
||||||
return .{ .track = E.HTMLTrackElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "ul")) {
|
|
||||||
return .{ .ulist = E.HTMLUListElement.init(base) };
|
|
||||||
} else if (std.mem.eql(u8, tag_name, "video")) {
|
|
||||||
return .{ .video = E.HTMLVideoElement.init(base) };
|
|
||||||
}
|
|
||||||
return .{ .unknown = E.HTMLUnknownElement.init(base) };
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Tests
|
// Tests
|
||||||
// -----
|
// -----
|
||||||
|
|
||||||
fn upper(comptime name: []const u8, comptime indexes: anytype) []u8 {
|
|
||||||
// indexes is [_]comptime_int
|
|
||||||
comptime {
|
|
||||||
var upper_name: [name.len]u8 = undefined;
|
|
||||||
for (name) |char, i| {
|
|
||||||
var toUpper = false;
|
|
||||||
for (indexes) |index| {
|
|
||||||
if (index == i) {
|
|
||||||
toUpper = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (toUpper) {
|
|
||||||
upper_name[i] = std.ascii.toUpper(char);
|
|
||||||
} else {
|
|
||||||
upper_name[i] = char;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &upper_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fn allUpper(comptime name: []const u8) []u8 {
|
|
||||||
// comptime {
|
|
||||||
// var upper_name: [name.len]u8 = undefined;
|
|
||||||
// for (name) |char, i| {
|
|
||||||
// upper_name[i] = std.ascii.toUpper(char);
|
|
||||||
// }
|
|
||||||
// return &upper_name;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn testExecFn(
|
pub fn testExecFn(
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
js_env: *jsruntime.Env,
|
js_env: *jsruntime.Env,
|
||||||
@@ -251,149 +77,29 @@ pub fn testExecFn(
|
|||||||
};
|
};
|
||||||
try checkCases(js_env, &getElementById);
|
try checkCases(js_env, &getElementById);
|
||||||
|
|
||||||
comptime var htmlElements = [_][]const u8{
|
const tags = comptime parser.Tag.all();
|
||||||
"a", // Anchor
|
const elements = comptime parser.Tag.allElements();
|
||||||
"area",
|
var createElements: [(tags.len - 1) * 3]Case = undefined;
|
||||||
"audio",
|
inline for (tags) |tag, i| {
|
||||||
"br", // BR
|
if (tag == .undef) {
|
||||||
"base",
|
continue;
|
||||||
"body",
|
|
||||||
"button",
|
|
||||||
"canvas",
|
|
||||||
"dl", // DList
|
|
||||||
"dialog",
|
|
||||||
"data",
|
|
||||||
"div",
|
|
||||||
"embed",
|
|
||||||
"fieldset", // FieldSet
|
|
||||||
"form",
|
|
||||||
"frameset", // FrameSet
|
|
||||||
"hr", // HR
|
|
||||||
"head",
|
|
||||||
"h1", // Heading
|
|
||||||
"h2", // Heading
|
|
||||||
"h3", // Heading
|
|
||||||
"h4", // Heading
|
|
||||||
"h5", // Heading
|
|
||||||
"h6", // Heading
|
|
||||||
"html",
|
|
||||||
"iframe", // IFrame
|
|
||||||
"img", // Image
|
|
||||||
"input",
|
|
||||||
"li", // LI
|
|
||||||
"label",
|
|
||||||
"legend",
|
|
||||||
"link",
|
|
||||||
"map",
|
|
||||||
"meta",
|
|
||||||
"meter",
|
|
||||||
"ins", // Mod
|
|
||||||
"del", // Mod
|
|
||||||
"ol", // OList
|
|
||||||
"object",
|
|
||||||
"optgroup", // OptGroup
|
|
||||||
"option",
|
|
||||||
"output",
|
|
||||||
"p", // Paragraph
|
|
||||||
"picture",
|
|
||||||
"pre",
|
|
||||||
"progress",
|
|
||||||
"blockquote", // Quote
|
|
||||||
"q", // Quote
|
|
||||||
"script",
|
|
||||||
"select",
|
|
||||||
"source",
|
|
||||||
"span",
|
|
||||||
"style",
|
|
||||||
"table",
|
|
||||||
"caption", // TableCaption
|
|
||||||
"th", // TableCell
|
|
||||||
"td", // TableCell
|
|
||||||
"col", // TableCol
|
|
||||||
"tr", // TableRow
|
|
||||||
"thead", // TableSection
|
|
||||||
"tbody", // TableSection
|
|
||||||
"tfoot", // TableSection
|
|
||||||
"template",
|
|
||||||
"textarea", // TextArea
|
|
||||||
"time",
|
|
||||||
"title",
|
|
||||||
"track",
|
|
||||||
"ul", // UList
|
|
||||||
"video",
|
|
||||||
};
|
|
||||||
var createElement: [htmlElements.len * 3]Case = undefined;
|
|
||||||
inline for (htmlElements) |elem, i| {
|
|
||||||
var upperName: []const u8 = undefined;
|
|
||||||
if (std.mem.eql(u8, elem, "a")) {
|
|
||||||
upperName = "Anchor";
|
|
||||||
} else if (std.mem.eql(u8, elem, "dl")) {
|
|
||||||
upperName = "DList";
|
|
||||||
} else if (std.mem.eql(u8, elem, "fieldset")) {
|
|
||||||
upperName = "FieldSet";
|
|
||||||
} else if (std.mem.eql(u8, elem, "frameset")) {
|
|
||||||
upperName = "FrameSet";
|
|
||||||
} else if (std.mem.eql(u8, elem, "h1") or
|
|
||||||
std.mem.eql(u8, elem, "h2") or
|
|
||||||
std.mem.eql(u8, elem, "h3") or
|
|
||||||
std.mem.eql(u8, elem, "h4") or
|
|
||||||
std.mem.eql(u8, elem, "h5") or
|
|
||||||
std.mem.eql(u8, elem, "h6"))
|
|
||||||
{
|
|
||||||
upperName = "Heading";
|
|
||||||
} else if (std.mem.eql(u8, elem, "iframe")) {
|
|
||||||
upperName = "IFrame";
|
|
||||||
} else if (std.mem.eql(u8, elem, "img")) {
|
|
||||||
upperName = "Image";
|
|
||||||
} else if (std.mem.eql(u8, elem, "del") or std.mem.eql(u8, elem, "ins")) {
|
|
||||||
upperName = "Mod";
|
|
||||||
} else if (std.mem.eql(u8, elem, "ol")) {
|
|
||||||
upperName = "OList";
|
|
||||||
} else if (std.mem.eql(u8, elem, "optgroup")) {
|
|
||||||
upperName = "OptGroup";
|
|
||||||
} else if (std.mem.eql(u8, elem, "p")) {
|
|
||||||
upperName = "Paragraph";
|
|
||||||
} else if (std.mem.eql(u8, elem, "blockquote") or std.mem.eql(u8, elem, "q")) {
|
|
||||||
upperName = "Quote";
|
|
||||||
} else if (std.mem.eql(u8, elem, "caption")) {
|
|
||||||
upperName = "TableCaption";
|
|
||||||
} else if (std.mem.eql(u8, elem, "th") or std.mem.eql(u8, elem, "td")) {
|
|
||||||
upperName = "TableCell";
|
|
||||||
} else if (std.mem.eql(u8, elem, "col")) {
|
|
||||||
upperName = "TableCol";
|
|
||||||
} else if (std.mem.eql(u8, elem, "tr")) {
|
|
||||||
upperName = "TableRow";
|
|
||||||
} else if (std.mem.eql(u8, elem, "thead") or
|
|
||||||
std.mem.eql(u8, elem, "tbody") or
|
|
||||||
std.mem.eql(u8, elem, "tfoot"))
|
|
||||||
{
|
|
||||||
upperName = "TableSection";
|
|
||||||
} else if (std.mem.eql(u8, elem, "textarea")) {
|
|
||||||
upperName = "TextArea";
|
|
||||||
} else if (std.mem.eql(u8, elem, "ul")) {
|
|
||||||
upperName = "UList";
|
|
||||||
} else {
|
|
||||||
if (elem.len == 2) {
|
|
||||||
upperName = upper(elem, [_]comptime_int{ 0, 1 });
|
|
||||||
} else {
|
|
||||||
upperName = upper(elem, [_]comptime_int{0});
|
|
||||||
}
|
}
|
||||||
}
|
const tag_name = @tagName(tag);
|
||||||
|
const element_name = elements[i];
|
||||||
createElement[i * 3] = Case{
|
createElements[i * 3] = Case{
|
||||||
.src = try std.fmt.allocPrint(alloc, "var {s}Elem = document.createElement('{s}')", .{ elem, elem }),
|
.src = try std.fmt.allocPrint(alloc, "var {s}Elem = document.createElement('{s}')", .{ tag_name, tag_name }),
|
||||||
.ex = "undefined",
|
.ex = "undefined",
|
||||||
};
|
};
|
||||||
createElement[(i * 3) + 1] = Case{
|
createElements[(i * 3) + 1] = Case{
|
||||||
.src = try std.fmt.allocPrint(alloc, "{s}Elem.constructor.name", .{elem}),
|
.src = try std.fmt.allocPrint(alloc, "{s}Elem.constructor.name", .{tag_name}),
|
||||||
.ex = try std.fmt.allocPrint(alloc, "HTML{s}Element", .{upperName}),
|
.ex = try std.fmt.allocPrint(alloc, "HTML{s}Element", .{element_name}),
|
||||||
};
|
};
|
||||||
createElement[(i * 3) + 2] = Case{
|
createElements[(i * 3) + 2] = Case{
|
||||||
.src = try std.fmt.allocPrint(alloc, "{s}Elem.localName", .{elem}),
|
.src = try std.fmt.allocPrint(alloc, "{s}Elem.localName", .{tag_name}),
|
||||||
.ex = elem,
|
.ex = tag_name,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
try checkCases(js_env, &createElement);
|
try checkCases(js_env, &createElements);
|
||||||
|
|
||||||
var unknown = [_]Case{
|
var unknown = [_]Case{
|
||||||
.{ .src = "let unknown = document.createElement('unknown')", .ex = "undefined" },
|
.{ .src = "let unknown = document.createElement('unknown')", .ex = "undefined" },
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const parser = @import("../parser.zig");
|
const parser = @import("../parser.zig");
|
||||||
|
const generate = @import("../generate.zig");
|
||||||
|
|
||||||
const Element = @import("../dom/element.zig").Element;
|
const Element = @import("../dom/element.zig").Element;
|
||||||
|
|
||||||
@@ -15,132 +16,71 @@ pub const HTMLElement = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const HTMLElementsTags = enum {
|
pub const HTMLElementsTypes = .{
|
||||||
unknown,
|
HTMLUnknownElement,
|
||||||
anchor,
|
HTMLAnchorElement,
|
||||||
area,
|
HTMLAreaElement,
|
||||||
audio,
|
HTMLAudioElement,
|
||||||
br,
|
HTMLBRElement,
|
||||||
base,
|
HTMLBaseElement,
|
||||||
body,
|
HTMLBodyElement,
|
||||||
button,
|
HTMLButtonElement,
|
||||||
canvas,
|
HTMLCanvasElement,
|
||||||
dlist,
|
HTMLDListElement,
|
||||||
dialog,
|
HTMLDialogElement,
|
||||||
data,
|
HTMLDataElement,
|
||||||
div,
|
HTMLDivElement,
|
||||||
embed,
|
HTMLEmbedElement,
|
||||||
fieldset,
|
HTMLFieldSetElement,
|
||||||
form,
|
HTMLFormElement,
|
||||||
frameset,
|
HTMLFrameSetElement,
|
||||||
hr,
|
HTMLHRElement,
|
||||||
head,
|
HTMLHeadElement,
|
||||||
heading,
|
HTMLHeadingElement,
|
||||||
html,
|
HTMLHtmlElement,
|
||||||
iframe,
|
HTMLIFrameElement,
|
||||||
img,
|
HTMLImageElement,
|
||||||
input,
|
HTMLInputElement,
|
||||||
li,
|
HTMLLIElement,
|
||||||
label,
|
HTMLLabelElement,
|
||||||
legend,
|
HTMLLegendElement,
|
||||||
link,
|
HTMLLinkElement,
|
||||||
map,
|
HTMLMapElement,
|
||||||
meta,
|
HTMLMetaElement,
|
||||||
meter,
|
HTMLMeterElement,
|
||||||
mod,
|
HTMLModElement,
|
||||||
olist,
|
HTMLOListElement,
|
||||||
object,
|
HTMLObjectElement,
|
||||||
optgroup,
|
HTMLOptGroupElement,
|
||||||
option,
|
HTMLOptionElement,
|
||||||
output,
|
HTMLOutputElement,
|
||||||
paragraph,
|
HTMLParagraphElement,
|
||||||
picture,
|
HTMLPictureElement,
|
||||||
pre,
|
HTMLPreElement,
|
||||||
progress,
|
HTMLProgressElement,
|
||||||
quote,
|
HTMLQuoteElement,
|
||||||
script,
|
HTMLScriptElement,
|
||||||
select,
|
HTMLSelectElement,
|
||||||
source,
|
HTMLSourceElement,
|
||||||
span,
|
HTMLSpanElement,
|
||||||
style,
|
HTMLStyleElement,
|
||||||
table,
|
HTMLTableElement,
|
||||||
tablecaption,
|
HTMLTableCaptionElement,
|
||||||
tablecell,
|
HTMLTableCellElement,
|
||||||
tablecol,
|
HTMLTableColElement,
|
||||||
tablerow,
|
HTMLTableRowElement,
|
||||||
tablesection,
|
HTMLTableSectionElement,
|
||||||
template,
|
HTMLTemplateElement,
|
||||||
textarea,
|
HTMLTextAreaElement,
|
||||||
time,
|
HTMLTimeElement,
|
||||||
title,
|
HTMLTitleElement,
|
||||||
track,
|
HTMLTrackElement,
|
||||||
ulist,
|
HTMLUListElement,
|
||||||
video,
|
HTMLVideoElement,
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: generate comptime?
|
|
||||||
pub const HTMLElements = union(HTMLElementsTags) {
|
|
||||||
unknown: HTMLUnknownElement,
|
|
||||||
anchor: HTMLAnchorElement,
|
|
||||||
area: HTMLAreaElement,
|
|
||||||
audio: HTMLAudioElement,
|
|
||||||
br: HTMLBRElement,
|
|
||||||
base: HTMLBaseElement,
|
|
||||||
body: HTMLBodyElement,
|
|
||||||
button: HTMLButtonElement,
|
|
||||||
canvas: HTMLCanvasElement,
|
|
||||||
dlist: HTMLDListElement,
|
|
||||||
dialog: HTMLDialogElement,
|
|
||||||
data: HTMLDataElement,
|
|
||||||
div: HTMLDivElement,
|
|
||||||
embed: HTMLEmbedElement,
|
|
||||||
fieldset: HTMLFieldSetElement,
|
|
||||||
form: HTMLFormElement,
|
|
||||||
frameset: HTMLFrameSetElement,
|
|
||||||
hr: HTMLHRElement,
|
|
||||||
head: HTMLHeadElement,
|
|
||||||
heading: HTMLHeadingElement,
|
|
||||||
html: HTMLHtmlElement,
|
|
||||||
iframe: HTMLIFrameElement,
|
|
||||||
img: HTMLImageElement,
|
|
||||||
input: HTMLInputElement,
|
|
||||||
li: HTMLLIElement,
|
|
||||||
label: HTMLLabelElement,
|
|
||||||
legend: HTMLLegendElement,
|
|
||||||
link: HTMLLinkElement,
|
|
||||||
map: HTMLMapElement,
|
|
||||||
meta: HTMLMetaElement,
|
|
||||||
meter: HTMLMeterElement,
|
|
||||||
mod: HTMLModElement,
|
|
||||||
olist: HTMLOListElement,
|
|
||||||
object: HTMLObjectElement,
|
|
||||||
optgroup: HTMLOptGroupElement,
|
|
||||||
option: HTMLOptionElement,
|
|
||||||
output: HTMLOutputElement,
|
|
||||||
paragraph: HTMLParagraphElement,
|
|
||||||
picture: HTMLPictureElement,
|
|
||||||
pre: HTMLPreElement,
|
|
||||||
progress: HTMLProgressElement,
|
|
||||||
quote: HTMLQuoteElement,
|
|
||||||
script: HTMLScriptElement,
|
|
||||||
select: HTMLSelectElement,
|
|
||||||
source: HTMLSourceElement,
|
|
||||||
span: HTMLSpanElement,
|
|
||||||
style: HTMLStyleElement,
|
|
||||||
table: HTMLTableElement,
|
|
||||||
tablecaption: HTMLTableCaptionElement,
|
|
||||||
tablecell: HTMLTableCellElement,
|
|
||||||
tablecol: HTMLTableColElement,
|
|
||||||
tablerow: HTMLTableRowElement,
|
|
||||||
tablesection: HTMLTableSectionElement,
|
|
||||||
template: HTMLTemplateElement,
|
|
||||||
textarea: HTMLTextAreaElement,
|
|
||||||
time: HTMLTimeElement,
|
|
||||||
title: HTMLTitleElement,
|
|
||||||
track: HTMLTrackElement,
|
|
||||||
ulist: HTMLUListElement,
|
|
||||||
video: HTMLVideoElement,
|
|
||||||
};
|
};
|
||||||
|
const HTMLElementsGenerated = generate.Union.compile(HTMLElementsTypes);
|
||||||
|
pub const HTMLElements = HTMLElementsGenerated._union;
|
||||||
|
pub const HTMLElementsTags = HTMLElementsGenerated._enum;
|
||||||
|
|
||||||
// Deprecated HTMLElements in Chrome (2023/03/15)
|
// Deprecated HTMLElements in Chrome (2023/03/15)
|
||||||
// HTMLContentelement
|
// HTMLContentelement
|
||||||
@@ -761,3 +701,69 @@ pub const HTMLVideoElement = struct {
|
|||||||
return .{ .proto = HTMLMediaElement.init(elem_base) };
|
return .{ .proto = HTMLMediaElement.init(elem_base) };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn ElementToHTMLElementInterface(base: *parser.Element) HTMLElements {
|
||||||
|
const tag = parser.nodeTag(parser.elementNode(base));
|
||||||
|
return switch (tag) {
|
||||||
|
.a => .{ .HTMLAnchorElement = HTMLAnchorElement.init(base) },
|
||||||
|
.area => .{ .HTMLAreaElement = HTMLAreaElement.init(base) },
|
||||||
|
.audio => .{ .HTMLAudioElement = HTMLAudioElement.init(base) },
|
||||||
|
.br => .{ .HTMLBRElement = HTMLBRElement.init(base) },
|
||||||
|
.base => .{ .HTMLBaseElement = HTMLBaseElement.init(base) },
|
||||||
|
.body => .{ .HTMLBodyElement = HTMLBodyElement.init(base) },
|
||||||
|
.button => .{ .HTMLButtonElement = HTMLButtonElement.init(base) },
|
||||||
|
.canvas => .{ .HTMLCanvasElement = HTMLCanvasElement.init(base) },
|
||||||
|
.dl => .{ .HTMLDListElement = HTMLDListElement.init(base) },
|
||||||
|
.dialog => .{ .HTMLDialogElement = HTMLDialogElement.init(base) },
|
||||||
|
.data => .{ .HTMLDataElement = HTMLDataElement.init(base) },
|
||||||
|
.div => .{ .HTMLDivElement = HTMLDivElement.init(base) },
|
||||||
|
.embed => .{ .HTMLEmbedElement = HTMLEmbedElement.init(base) },
|
||||||
|
.fieldset => .{ .HTMLFieldSetElement = HTMLFieldSetElement.init(base) },
|
||||||
|
.form => .{ .HTMLFormElement = HTMLFormElement.init(base) },
|
||||||
|
.frameset => .{ .HTMLFrameSetElement = HTMLFrameSetElement.init(base) },
|
||||||
|
.hr => .{ .HTMLHRElement = HTMLHRElement.init(base) },
|
||||||
|
.head => .{ .HTMLHeadElement = HTMLHeadElement.init(base) },
|
||||||
|
.h1, .h2, .h3, .h4, .h5, .h6 => .{ .HTMLHeadingElement = HTMLHeadingElement.init(base) },
|
||||||
|
.html => .{ .HTMLHtmlElement = HTMLHtmlElement.init(base) },
|
||||||
|
.iframe => .{ .HTMLIFrameElement = HTMLIFrameElement.init(base) },
|
||||||
|
.img => .{ .HTMLImageElement = HTMLImageElement.init(base) },
|
||||||
|
.input => .{ .HTMLInputElement = HTMLInputElement.init(base) },
|
||||||
|
.li => .{ .HTMLLIElement = HTMLLIElement.init(base) },
|
||||||
|
.label => .{ .HTMLLabelElement = HTMLLabelElement.init(base) },
|
||||||
|
.legend => .{ .HTMLLegendElement = HTMLLegendElement.init(base) },
|
||||||
|
.link => .{ .HTMLLinkElement = HTMLLinkElement.init(base) },
|
||||||
|
.map => .{ .HTMLMapElement = HTMLMapElement.init(base) },
|
||||||
|
.meta => .{ .HTMLMetaElement = HTMLMetaElement.init(base) },
|
||||||
|
.meter => .{ .HTMLMeterElement = HTMLMeterElement.init(base) },
|
||||||
|
.ins, .del => .{ .HTMLModElement = HTMLModElement.init(base) },
|
||||||
|
.ol => .{ .HTMLOListElement = HTMLOListElement.init(base) },
|
||||||
|
.object => .{ .HTMLObjectElement = HTMLObjectElement.init(base) },
|
||||||
|
.optgroup => .{ .HTMLOptGroupElement = HTMLOptGroupElement.init(base) },
|
||||||
|
.option => .{ .HTMLOptionElement = HTMLOptionElement.init(base) },
|
||||||
|
.output => .{ .HTMLOutputElement = HTMLOutputElement.init(base) },
|
||||||
|
.p => .{ .HTMLParagraphElement = HTMLParagraphElement.init(base) },
|
||||||
|
.picture => .{ .HTMLPictureElement = HTMLPictureElement.init(base) },
|
||||||
|
.pre => .{ .HTMLPreElement = HTMLPreElement.init(base) },
|
||||||
|
.progress => .{ .HTMLProgressElement = HTMLProgressElement.init(base) },
|
||||||
|
.blockquote, .q => .{ .HTMLQuoteElement = HTMLQuoteElement.init(base) },
|
||||||
|
.script => .{ .HTMLScriptElement = HTMLScriptElement.init(base) },
|
||||||
|
.select => .{ .HTMLSelectElement = HTMLSelectElement.init(base) },
|
||||||
|
.source => .{ .HTMLSourceElement = HTMLSourceElement.init(base) },
|
||||||
|
.span => .{ .HTMLSpanElement = HTMLSpanElement.init(base) },
|
||||||
|
.style => .{ .HTMLStyleElement = HTMLStyleElement.init(base) },
|
||||||
|
.table => .{ .HTMLTableElement = HTMLTableElement.init(base) },
|
||||||
|
.caption => .{ .HTMLTableCaptionElement = HTMLTableCaptionElement.init(base) },
|
||||||
|
.th, .td => .{ .HTMLTableCellElement = HTMLTableCellElement.init(base) },
|
||||||
|
.col => .{ .HTMLTableColElement = HTMLTableColElement.init(base) },
|
||||||
|
.tr => .{ .HTMLTableRowElement = HTMLTableRowElement.init(base) },
|
||||||
|
.thead, .tbody, .tfoot => .{ .HTMLTableSectionElement = HTMLTableSectionElement.init(base) },
|
||||||
|
.template => .{ .HTMLTemplateElement = HTMLTemplateElement.init(base) },
|
||||||
|
.textarea => .{ .HTMLTextAreaElement = HTMLTextAreaElement.init(base) },
|
||||||
|
.time => .{ .HTMLTimeElement = HTMLTimeElement.init(base) },
|
||||||
|
.title => .{ .HTMLTitleElement = HTMLTitleElement.init(base) },
|
||||||
|
.track => .{ .HTMLTrackElement = HTMLTrackElement.init(base) },
|
||||||
|
.ul => .{ .HTMLUListElement = HTMLUListElement.init(base) },
|
||||||
|
.video => .{ .HTMLVideoElement = HTMLVideoElement.init(base) },
|
||||||
|
.undef => .{ .HTMLUnknownElement = HTMLUnknownElement.init(base) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
147
src/parser.zig
147
src/parser.zig
@@ -7,6 +7,149 @@ const c = @cImport({
|
|||||||
// Public API
|
// Public API
|
||||||
// ----------
|
// ----------
|
||||||
|
|
||||||
|
// Tag
|
||||||
|
|
||||||
|
pub const Tag = enum(u8) {
|
||||||
|
a = c.LXB_TAG_A,
|
||||||
|
area = c.LXB_TAG_AREA,
|
||||||
|
audio = c.LXB_TAG_AUDIO,
|
||||||
|
br = c.LXB_TAG_BR,
|
||||||
|
base = c.LXB_TAG_BASE,
|
||||||
|
body = c.LXB_TAG_BODY,
|
||||||
|
button = c.LXB_TAG_BUTTON,
|
||||||
|
canvas = c.LXB_TAG_CANVAS,
|
||||||
|
dl = c.LXB_TAG_DL,
|
||||||
|
dialog = c.LXB_TAG_DIALOG,
|
||||||
|
data = c.LXB_TAG_DATA,
|
||||||
|
div = c.LXB_TAG_DIV,
|
||||||
|
embed = c.LXB_TAG_EMBED,
|
||||||
|
fieldset = c.LXB_TAG_FIELDSET,
|
||||||
|
form = c.LXB_TAG_FORM,
|
||||||
|
frameset = c.LXB_TAG_FRAMESET,
|
||||||
|
hr = c.LXB_TAG_HR,
|
||||||
|
head = c.LXB_TAG_HEAD,
|
||||||
|
h1 = c.LXB_TAG_H1,
|
||||||
|
h2 = c.LXB_TAG_H2,
|
||||||
|
h3 = c.LXB_TAG_H3,
|
||||||
|
h4 = c.LXB_TAG_H4,
|
||||||
|
h5 = c.LXB_TAG_H5,
|
||||||
|
h6 = c.LXB_TAG_H6,
|
||||||
|
html = c.LXB_TAG_HTML,
|
||||||
|
iframe = c.LXB_TAG_IFRAME,
|
||||||
|
img = c.LXB_TAG_IMG,
|
||||||
|
input = c.LXB_TAG_INPUT,
|
||||||
|
li = c.LXB_TAG_LI,
|
||||||
|
label = c.LXB_TAG_LABEL,
|
||||||
|
legend = c.LXB_TAG_LEGEND,
|
||||||
|
link = c.LXB_TAG_LINK,
|
||||||
|
map = c.LXB_TAG_MAP,
|
||||||
|
meta = c.LXB_TAG_META,
|
||||||
|
meter = c.LXB_TAG_METER,
|
||||||
|
ins = c.LXB_TAG_INS,
|
||||||
|
del = c.LXB_TAG_DEL,
|
||||||
|
ol = c.LXB_TAG_OL,
|
||||||
|
object = c.LXB_TAG_OBJECT,
|
||||||
|
optgroup = c.LXB_TAG_OPTGROUP,
|
||||||
|
option = c.LXB_TAG_OPTION,
|
||||||
|
output = c.LXB_TAG_OUTPUT,
|
||||||
|
p = c.LXB_TAG_P,
|
||||||
|
picture = c.LXB_TAG_PICTURE,
|
||||||
|
pre = c.LXB_TAG_PRE,
|
||||||
|
progress = c.LXB_TAG_PROGRESS,
|
||||||
|
blockquote = c.LXB_TAG_BLOCKQUOTE,
|
||||||
|
q = c.LXB_TAG_Q,
|
||||||
|
script = c.LXB_TAG_SCRIPT,
|
||||||
|
select = c.LXB_TAG_SELECT,
|
||||||
|
source = c.LXB_TAG_SOURCE,
|
||||||
|
span = c.LXB_TAG_SPAN,
|
||||||
|
style = c.LXB_TAG_STYLE,
|
||||||
|
table = c.LXB_TAG_TABLE,
|
||||||
|
caption = c.LXB_TAG_CAPTION,
|
||||||
|
th = c.LXB_TAG_TH,
|
||||||
|
td = c.LXB_TAG_TD,
|
||||||
|
col = c.LXB_TAG_COL,
|
||||||
|
tr = c.LXB_TAG_TR,
|
||||||
|
thead = c.LXB_TAG_THEAD,
|
||||||
|
tbody = c.LXB_TAG_TBODY,
|
||||||
|
tfoot = c.LXB_TAG_TFOOT,
|
||||||
|
template = c.LXB_TAG_TEMPLATE,
|
||||||
|
textarea = c.LXB_TAG_TEXTAREA,
|
||||||
|
time = c.LXB_TAG_TIME,
|
||||||
|
title = c.LXB_TAG_TITLE,
|
||||||
|
track = c.LXB_TAG_TRACK,
|
||||||
|
ul = c.LXB_TAG_UL,
|
||||||
|
video = c.LXB_TAG_VIDEO,
|
||||||
|
undef = c.LXB_TAG__UNDEF,
|
||||||
|
|
||||||
|
pub fn all() []Tag {
|
||||||
|
comptime {
|
||||||
|
const info = @typeInfo(Tag).Enum;
|
||||||
|
comptime var l: [info.fields.len]Tag = undefined;
|
||||||
|
inline for (info.fields) |field, i| {
|
||||||
|
l[i] = @intToEnum(Tag, field.value);
|
||||||
|
}
|
||||||
|
return &l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allElements() [][]const u8 {
|
||||||
|
comptime {
|
||||||
|
const tags = all();
|
||||||
|
var names: [tags.len][]const u8 = undefined;
|
||||||
|
inline for (tags) |tag, i| {
|
||||||
|
names[i] = tag.elementName();
|
||||||
|
}
|
||||||
|
return &names;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upperName(comptime name: []const u8) []const u8 {
|
||||||
|
comptime {
|
||||||
|
var upper_name: [name.len]u8 = undefined;
|
||||||
|
for (name) |char, i| {
|
||||||
|
var to_upper = false;
|
||||||
|
if (i == 0) {
|
||||||
|
to_upper = true;
|
||||||
|
} else if (i == 1 and name.len == 2) {
|
||||||
|
to_upper = true;
|
||||||
|
}
|
||||||
|
if (to_upper) {
|
||||||
|
upper_name[i] = std.ascii.toUpper(char);
|
||||||
|
} else {
|
||||||
|
upper_name[i] = char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &upper_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn elementName(comptime tag: Tag) []const u8 {
|
||||||
|
return switch (tag) {
|
||||||
|
.area, .audio, .base, .body, .button, .br, .canvas, .dialog, .data, .div, .embed, .form, .head, .html, .hr, .input, .label, .li, .legend, .link, .map, .meta, .meter, .object, .option, .output, .picture, .pre, .progress, .script, .select, .source, .span, .style, .table, .template, .time, .title, .track, .video => upperName(@tagName(tag)),
|
||||||
|
.a => "Anchor",
|
||||||
|
.dl => "DList",
|
||||||
|
.fieldset => "FieldSet",
|
||||||
|
.frameset => "FrameSet",
|
||||||
|
.h1, .h2, .h3, .h4, .h5, .h6 => "Heading",
|
||||||
|
.iframe => "IFrame",
|
||||||
|
.img => "Image",
|
||||||
|
.ins, .del => "Mod",
|
||||||
|
.ol => "OList",
|
||||||
|
.optgroup => "OptGroup",
|
||||||
|
.p => "Paragraph",
|
||||||
|
.blockquote, .q => "Quote",
|
||||||
|
.caption => "TableCaption",
|
||||||
|
.th, .td => "TableCell",
|
||||||
|
.col => "TableCol",
|
||||||
|
.tr => "TableRow",
|
||||||
|
.thead, .tbody, .tfoot => "TableSection",
|
||||||
|
.textarea => "TextArea",
|
||||||
|
.ul => "UList",
|
||||||
|
.undef => "Unknown",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// EventTarget
|
// EventTarget
|
||||||
|
|
||||||
pub const EventTarget = c.lxb_dom_event_target_t;
|
pub const EventTarget = c.lxb_dom_event_target_t;
|
||||||
@@ -36,6 +179,10 @@ pub inline fn nodeEventTarget(node: *Node) *EventTarget {
|
|||||||
return c.lxb_dom_interface_event_target(node);
|
return c.lxb_dom_interface_event_target(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn nodeTag(node: *Node) Tag {
|
||||||
|
return @intToEnum(Tag, c.lxb_dom_node_tag_id(node));
|
||||||
|
}
|
||||||
|
|
||||||
pub const nodeWalker = (fn (node: ?*Node, _: ?*anyopaque) callconv(.C) Action);
|
pub const nodeWalker = (fn (node: ?*Node, _: ?*anyopaque) callconv(.C) Action);
|
||||||
|
|
||||||
pub inline fn nodeName(node: *Node) [*c]const u8 {
|
pub inline fn nodeName(node: *Node) [*c]const u8 {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const jsruntime = @import("jsruntime");
|
const jsruntime = @import("jsruntime");
|
||||||
|
const generate = @import("generate.zig");
|
||||||
|
|
||||||
const DOM = @import("dom.zig");
|
const DOM = @import("dom.zig");
|
||||||
const testExecFn = @import("html/document.zig").testExecFn;
|
const testExecFn = @import("html/document.zig").testExecFn;
|
||||||
@@ -27,6 +28,11 @@ fn testsExecFn(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
|
std.debug.print("\n", .{});
|
||||||
|
|
||||||
|
// generate tests
|
||||||
|
try generate.tests();
|
||||||
|
|
||||||
// generate APIs
|
// generate APIs
|
||||||
const apis = jsruntime.compile(DOM.Interfaces);
|
const apis = jsruntime.compile(DOM.Interfaces);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user