From fe1ccd974eff971a97638f948e8e1bf2f27c209c Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Wed, 19 Apr 2023 12:57:54 +0200 Subject: [PATCH 1/6] Use LXB_TAG to determine HTMLElement kind Signed-off-by: Francis Bouvier --- src/html/document.zig | 144 +----------------------------------------- src/html/elements.zig | 80 +++++++++++++++++++++++ 2 files changed, 81 insertions(+), 143 deletions(-) diff --git a/src/html/document.zig b/src/html/document.zig index e2e60d7d..be2a9f0c 100644 --- a/src/html/document.zig +++ b/src/html/document.zig @@ -50,149 +50,7 @@ pub const HTMLDocument = struct { pub fn _createElement(self: HTMLDocument, tag_name: []const u8) E.HTMLElements { const base = parser.documentCreateElement(self.proto.base.?, tag_name); - - // 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) }; + return E.ElementToHTMLElementInterface(base); } }; diff --git a/src/html/elements.zig b/src/html/elements.zig index 7d4db0d2..a8804a04 100644 --- a/src/html/elements.zig +++ b/src/html/elements.zig @@ -761,3 +761,83 @@ pub const HTMLVideoElement = struct { return .{ .proto = HTMLMediaElement.init(elem_base) }; } }; + +const c = @cImport({ + @cInclude("lexbor/html/html.h"); +}); + +pub fn ElementToHTMLElementInterface(base: *parser.Element) HTMLElements { + return switch (base.*.node.local_name) { + c.LXB_TAG_A => .{ .anchor = HTMLAnchorElement.init(base) }, + c.LXB_TAG_AREA => .{ .area = HTMLAreaElement.init(base) }, + c.LXB_TAG_AUDIO => .{ .audio = HTMLAudioElement.init(base) }, + c.LXB_TAG_BR => .{ .br = HTMLBRElement.init(base) }, + c.LXB_TAG_BASE => .{ .base = HTMLBaseElement.init(base) }, + c.LXB_TAG_BODY => .{ .body = HTMLBodyElement.init(base) }, + c.LXB_TAG_BUTTON => .{ .button = HTMLButtonElement.init(base) }, + c.LXB_TAG_CANVAS => .{ .canvas = HTMLCanvasElement.init(base) }, + c.LXB_TAG_DL => .{ .dlist = HTMLDListElement.init(base) }, + c.LXB_TAG_DIALOG => .{ .dialog = HTMLDialogElement.init(base) }, + c.LXB_TAG_DATA => .{ .data = HTMLDataElement.init(base) }, + c.LXB_TAG_DIV => .{ .div = HTMLDivElement.init(base) }, + c.LXB_TAG_EMBED => .{ .embed = HTMLEmbedElement.init(base) }, + c.LXB_TAG_FIELDSET => .{ .fieldset = HTMLFieldSetElement.init(base) }, + c.LXB_TAG_FORM => .{ .form = HTMLFormElement.init(base) }, + c.LXB_TAG_FRAMESET => .{ .frameset = HTMLFrameSetElement.init(base) }, + c.LXB_TAG_HR => .{ .hr = HTMLHRElement.init(base) }, + c.LXB_TAG_HEAD => .{ .head = HTMLHeadElement.init(base) }, + c.LXB_TAG_H1 => .{ .heading = HTMLHeadingElement.init(base) }, + c.LXB_TAG_H2 => .{ .heading = HTMLHeadingElement.init(base) }, + c.LXB_TAG_H3 => .{ .heading = HTMLHeadingElement.init(base) }, + c.LXB_TAG_H4 => .{ .heading = HTMLHeadingElement.init(base) }, + c.LXB_TAG_H5 => .{ .heading = HTMLHeadingElement.init(base) }, + c.LXB_TAG_H6 => .{ .heading = HTMLHeadingElement.init(base) }, + c.LXB_TAG_HTML => .{ .html = HTMLHtmlElement.init(base) }, + c.LXB_TAG_IFRAME => .{ .iframe = HTMLIFrameElement.init(base) }, + c.LXB_TAG_IMG => .{ .img = HTMLImageElement.init(base) }, + c.LXB_TAG_INPUT => .{ .input = HTMLInputElement.init(base) }, + c.LXB_TAG_LI => .{ .li = HTMLLIElement.init(base) }, + c.LXB_TAG_LABEL => .{ .label = HTMLLabelElement.init(base) }, + c.LXB_TAG_LEGEND => .{ .legend = HTMLLegendElement.init(base) }, + c.LXB_TAG_LINK => .{ .link = HTMLLinkElement.init(base) }, + c.LXB_TAG_MAP => .{ .map = HTMLMapElement.init(base) }, + c.LXB_TAG_META => .{ .meta = HTMLMetaElement.init(base) }, + c.LXB_TAG_METER => .{ .meter = HTMLMeterElement.init(base) }, + c.LXB_TAG_INS => .{ .mod = HTMLModElement.init(base) }, + c.LXB_TAG_DEL => .{ .mod = HTMLModElement.init(base) }, + c.LXB_TAG_OL => .{ .olist = HTMLOListElement.init(base) }, + c.LXB_TAG_OBJECT => .{ .object = HTMLObjectElement.init(base) }, + c.LXB_TAG_OPTGROUP => .{ .optgroup = HTMLOptGroupElement.init(base) }, + c.LXB_TAG_OPTION => .{ .option = HTMLOptionElement.init(base) }, + c.LXB_TAG_OUTPUT => .{ .output = HTMLOutputElement.init(base) }, + c.LXB_TAG_P => .{ .paragraph = HTMLParagraphElement.init(base) }, + c.LXB_TAG_PICTURE => .{ .picture = HTMLPictureElement.init(base) }, + c.LXB_TAG_PRE => .{ .pre = HTMLPreElement.init(base) }, + c.LXB_TAG_PROGRESS => .{ .progress = HTMLProgressElement.init(base) }, + c.LXB_TAG_BLOCKQUOTE => .{ .quote = HTMLQuoteElement.init(base) }, + c.LXB_TAG_Q => .{ .quote = HTMLQuoteElement.init(base) }, + c.LXB_TAG_SCRIPT => .{ .script = HTMLScriptElement.init(base) }, + c.LXB_TAG_SELECT => .{ .select = HTMLSelectElement.init(base) }, + c.LXB_TAG_SOURCE => .{ .source = HTMLSourceElement.init(base) }, + c.LXB_TAG_SPAN => .{ .span = HTMLSpanElement.init(base) }, + c.LXB_TAG_STYLE => .{ .style = HTMLStyleElement.init(base) }, + c.LXB_TAG_TABLE => .{ .table = HTMLTableElement.init(base) }, + c.LXB_TAG_CAPTION => .{ .tablecaption = HTMLTableCaptionElement.init(base) }, + c.LXB_TAG_TH => .{ .tablecell = HTMLTableCellElement.init(base) }, + c.LXB_TAG_TD => .{ .tablecell = HTMLTableCellElement.init(base) }, + c.LXB_TAG_COL => .{ .tablecol = HTMLTableColElement.init(base) }, + c.LXB_TAG_TR => .{ .tablerow = HTMLTableRowElement.init(base) }, + c.LXB_TAG_THEAD => .{ .tablesection = HTMLTableSectionElement.init(base) }, + c.LXB_TAG_TBODY => .{ .tablesection = HTMLTableSectionElement.init(base) }, + c.LXB_TAG_TFOOT => .{ .tablesection = HTMLTableSectionElement.init(base) }, + c.LXB_TAG_TEMPLATE => .{ .template = HTMLTemplateElement.init(base) }, + c.LXB_TAG_TEXTAREA => .{ .textarea = HTMLTextAreaElement.init(base) }, + c.LXB_TAG_TIME => .{ .time = HTMLTimeElement.init(base) }, + c.LXB_TAG_TITLE => .{ .title = HTMLTitleElement.init(base) }, + c.LXB_TAG_TRACK => .{ .track = HTMLTrackElement.init(base) }, + c.LXB_TAG_UL => .{ .ulist = HTMLUListElement.init(base) }, + c.LXB_TAG_VIDEO => .{ .video = HTMLVideoElement.init(base) }, + c.LXB_TAG__UNDEF => .{ .unknown = HTMLUnknownElement.init(base) }, + else => .{ .unknown = HTMLUnknownElement.init(base) }, + }; +} From 98796d9512fb4b6143502c4ff6092b0096b380c8 Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Mon, 15 May 2023 18:48:35 +0200 Subject: [PATCH 2/6] Add generate Union function Signed-off-by: Francis Bouvier --- src/generate.zig | 203 ++++++++++++++++++++++++++++++++++++++++++++++ src/run_tests.zig | 6 ++ 2 files changed, 209 insertions(+) create mode 100644 src/generate.zig diff --git a/src/generate.zig b/src/generate.zig new file mode 100644 index 00000000..a05e8a2e --- /dev/null +++ b/src/generate.zig @@ -0,0 +1,203 @@ +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(); +} + +pub const Union = struct { + _enum: type, + _union: type, + + pub fn compile(comptime tuple: anytype) Union { + comptime { + return private_compile(tuple) catch @compileError("CompileUnion error"); + } + } + + 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.GenerateUnionArgNotTuple; + } + + const tuple_members = tuple_info.Struct.fields; + + // first iteration to get the total number of members + comptime var members_nb = 0; + inline 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.GenerateUnionMemberNotUnionOrStruct; + } + } + + // define the tag type regarding the members nb + comptime 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.GenerateUnionTooMuchMembers; + } + + // second iteration to generate tags + comptime var enum_fields: [members_nb]std.builtin.Type.EnumField = undefined; + comptime var done = 0; + inline 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; + inline 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 + comptime var union_fields: [members_nb]std.builtin.Type.UnionField = undefined; + done = 0; + inline 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; + inline 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, + }; + } +}; + +// Tests +// ----- + +const Error = error{ + UnionArgNotTuple, + UnionMemberNotUnionOrStruct, + UnionTooMuchMembers, +}; + +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", .{}); +} diff --git a/src/run_tests.zig b/src/run_tests.zig index 4732b172..8fbac87b 100644 --- a/src/run_tests.zig +++ b/src/run_tests.zig @@ -1,6 +1,7 @@ const std = @import("std"); const jsruntime = @import("jsruntime"); +const generate = @import("generate.zig"); const DOM = @import("dom.zig"); const testExecFn = @import("html/document.zig").testExecFn; @@ -27,6 +28,11 @@ fn testsExecFn( } test { + std.debug.print("\n", .{}); + + // generate tests + try generate.tests(); + // generate APIs const apis = jsruntime.compile(DOM.Interfaces); From 12b840b3d5337aab5b103a648a7e416bfc6ddfe5 Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Thu, 18 May 2023 16:32:42 +0200 Subject: [PATCH 3/6] Add parser Tag Signed-off-by: Francis Bouvier --- src/html/document.zig | 186 ++++-------------------------------------- src/html/elements.zig | 138 ++++++++++++++----------------- src/parser.zig | 147 +++++++++++++++++++++++++++++++++ 3 files changed, 226 insertions(+), 245 deletions(-) diff --git a/src/html/document.zig b/src/html/document.zig index be2a9f0c..deee09c3 100644 --- a/src/html/document.zig +++ b/src/html/document.zig @@ -57,38 +57,6 @@ pub const HTMLDocument = struct { // 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( alloc: std.mem.Allocator, js_env: *jsruntime.Env, @@ -109,149 +77,29 @@ pub fn testExecFn( }; try checkCases(js_env, &getElementById); - comptime var htmlElements = [_][]const u8{ - "a", // Anchor - "area", - "audio", - "br", // BR - "base", - "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 tags = comptime parser.Tag.all(); + const elements = comptime parser.Tag.allElements(); + var createElements: [(tags.len - 1) * 3]Case = undefined; + inline for (tags) |tag, i| { + if (tag == .undef) { + continue; } - - createElement[i * 3] = Case{ - .src = try std.fmt.allocPrint(alloc, "var {s}Elem = document.createElement('{s}')", .{ elem, elem }), + const tag_name = @tagName(tag); + const element_name = elements[i]; + createElements[i * 3] = Case{ + .src = try std.fmt.allocPrint(alloc, "var {s}Elem = document.createElement('{s}')", .{ tag_name, tag_name }), .ex = "undefined", }; - createElement[(i * 3) + 1] = Case{ - .src = try std.fmt.allocPrint(alloc, "{s}Elem.constructor.name", .{elem}), - .ex = try std.fmt.allocPrint(alloc, "HTML{s}Element", .{upperName}), + createElements[(i * 3) + 1] = Case{ + .src = try std.fmt.allocPrint(alloc, "{s}Elem.constructor.name", .{tag_name}), + .ex = try std.fmt.allocPrint(alloc, "HTML{s}Element", .{element_name}), }; - createElement[(i * 3) + 2] = Case{ - .src = try std.fmt.allocPrint(alloc, "{s}Elem.localName", .{elem}), - .ex = elem, + createElements[(i * 3) + 2] = Case{ + .src = try std.fmt.allocPrint(alloc, "{s}Elem.localName", .{tag_name}), + .ex = tag_name, }; } - try checkCases(js_env, &createElement); + try checkCases(js_env, &createElements); var unknown = [_]Case{ .{ .src = "let unknown = document.createElement('unknown')", .ex = "undefined" }, diff --git a/src/html/elements.zig b/src/html/elements.zig index a8804a04..a44973cd 100644 --- a/src/html/elements.zig +++ b/src/html/elements.zig @@ -762,82 +762,68 @@ pub const HTMLVideoElement = struct { } }; -const c = @cImport({ - @cInclude("lexbor/html/html.h"); -}); - pub fn ElementToHTMLElementInterface(base: *parser.Element) HTMLElements { - return switch (base.*.node.local_name) { - c.LXB_TAG_A => .{ .anchor = HTMLAnchorElement.init(base) }, - c.LXB_TAG_AREA => .{ .area = HTMLAreaElement.init(base) }, - c.LXB_TAG_AUDIO => .{ .audio = HTMLAudioElement.init(base) }, - c.LXB_TAG_BR => .{ .br = HTMLBRElement.init(base) }, - c.LXB_TAG_BASE => .{ .base = HTMLBaseElement.init(base) }, - c.LXB_TAG_BODY => .{ .body = HTMLBodyElement.init(base) }, - c.LXB_TAG_BUTTON => .{ .button = HTMLButtonElement.init(base) }, - c.LXB_TAG_CANVAS => .{ .canvas = HTMLCanvasElement.init(base) }, - c.LXB_TAG_DL => .{ .dlist = HTMLDListElement.init(base) }, - c.LXB_TAG_DIALOG => .{ .dialog = HTMLDialogElement.init(base) }, - c.LXB_TAG_DATA => .{ .data = HTMLDataElement.init(base) }, - c.LXB_TAG_DIV => .{ .div = HTMLDivElement.init(base) }, - c.LXB_TAG_EMBED => .{ .embed = HTMLEmbedElement.init(base) }, - c.LXB_TAG_FIELDSET => .{ .fieldset = HTMLFieldSetElement.init(base) }, - c.LXB_TAG_FORM => .{ .form = HTMLFormElement.init(base) }, - c.LXB_TAG_FRAMESET => .{ .frameset = HTMLFrameSetElement.init(base) }, - c.LXB_TAG_HR => .{ .hr = HTMLHRElement.init(base) }, - c.LXB_TAG_HEAD => .{ .head = HTMLHeadElement.init(base) }, - c.LXB_TAG_H1 => .{ .heading = HTMLHeadingElement.init(base) }, - c.LXB_TAG_H2 => .{ .heading = HTMLHeadingElement.init(base) }, - c.LXB_TAG_H3 => .{ .heading = HTMLHeadingElement.init(base) }, - c.LXB_TAG_H4 => .{ .heading = HTMLHeadingElement.init(base) }, - c.LXB_TAG_H5 => .{ .heading = HTMLHeadingElement.init(base) }, - c.LXB_TAG_H6 => .{ .heading = HTMLHeadingElement.init(base) }, - c.LXB_TAG_HTML => .{ .html = HTMLHtmlElement.init(base) }, - c.LXB_TAG_IFRAME => .{ .iframe = HTMLIFrameElement.init(base) }, - c.LXB_TAG_IMG => .{ .img = HTMLImageElement.init(base) }, - c.LXB_TAG_INPUT => .{ .input = HTMLInputElement.init(base) }, - c.LXB_TAG_LI => .{ .li = HTMLLIElement.init(base) }, - c.LXB_TAG_LABEL => .{ .label = HTMLLabelElement.init(base) }, - c.LXB_TAG_LEGEND => .{ .legend = HTMLLegendElement.init(base) }, - c.LXB_TAG_LINK => .{ .link = HTMLLinkElement.init(base) }, - c.LXB_TAG_MAP => .{ .map = HTMLMapElement.init(base) }, - c.LXB_TAG_META => .{ .meta = HTMLMetaElement.init(base) }, - c.LXB_TAG_METER => .{ .meter = HTMLMeterElement.init(base) }, - c.LXB_TAG_INS => .{ .mod = HTMLModElement.init(base) }, - c.LXB_TAG_DEL => .{ .mod = HTMLModElement.init(base) }, - c.LXB_TAG_OL => .{ .olist = HTMLOListElement.init(base) }, - c.LXB_TAG_OBJECT => .{ .object = HTMLObjectElement.init(base) }, - c.LXB_TAG_OPTGROUP => .{ .optgroup = HTMLOptGroupElement.init(base) }, - c.LXB_TAG_OPTION => .{ .option = HTMLOptionElement.init(base) }, - c.LXB_TAG_OUTPUT => .{ .output = HTMLOutputElement.init(base) }, - c.LXB_TAG_P => .{ .paragraph = HTMLParagraphElement.init(base) }, - c.LXB_TAG_PICTURE => .{ .picture = HTMLPictureElement.init(base) }, - c.LXB_TAG_PRE => .{ .pre = HTMLPreElement.init(base) }, - c.LXB_TAG_PROGRESS => .{ .progress = HTMLProgressElement.init(base) }, - c.LXB_TAG_BLOCKQUOTE => .{ .quote = HTMLQuoteElement.init(base) }, - c.LXB_TAG_Q => .{ .quote = HTMLQuoteElement.init(base) }, - c.LXB_TAG_SCRIPT => .{ .script = HTMLScriptElement.init(base) }, - c.LXB_TAG_SELECT => .{ .select = HTMLSelectElement.init(base) }, - c.LXB_TAG_SOURCE => .{ .source = HTMLSourceElement.init(base) }, - c.LXB_TAG_SPAN => .{ .span = HTMLSpanElement.init(base) }, - c.LXB_TAG_STYLE => .{ .style = HTMLStyleElement.init(base) }, - c.LXB_TAG_TABLE => .{ .table = HTMLTableElement.init(base) }, - c.LXB_TAG_CAPTION => .{ .tablecaption = HTMLTableCaptionElement.init(base) }, - c.LXB_TAG_TH => .{ .tablecell = HTMLTableCellElement.init(base) }, - c.LXB_TAG_TD => .{ .tablecell = HTMLTableCellElement.init(base) }, - c.LXB_TAG_COL => .{ .tablecol = HTMLTableColElement.init(base) }, - c.LXB_TAG_TR => .{ .tablerow = HTMLTableRowElement.init(base) }, - c.LXB_TAG_THEAD => .{ .tablesection = HTMLTableSectionElement.init(base) }, - c.LXB_TAG_TBODY => .{ .tablesection = HTMLTableSectionElement.init(base) }, - c.LXB_TAG_TFOOT => .{ .tablesection = HTMLTableSectionElement.init(base) }, - c.LXB_TAG_TEMPLATE => .{ .template = HTMLTemplateElement.init(base) }, - c.LXB_TAG_TEXTAREA => .{ .textarea = HTMLTextAreaElement.init(base) }, - c.LXB_TAG_TIME => .{ .time = HTMLTimeElement.init(base) }, - c.LXB_TAG_TITLE => .{ .title = HTMLTitleElement.init(base) }, - c.LXB_TAG_TRACK => .{ .track = HTMLTrackElement.init(base) }, - c.LXB_TAG_UL => .{ .ulist = HTMLUListElement.init(base) }, - c.LXB_TAG_VIDEO => .{ .video = HTMLVideoElement.init(base) }, - c.LXB_TAG__UNDEF => .{ .unknown = HTMLUnknownElement.init(base) }, - else => .{ .unknown = HTMLUnknownElement.init(base) }, + const tag = parser.nodeTag(parser.elementNode(base)); + return switch (tag) { + .a => .{ .anchor = HTMLAnchorElement.init(base) }, + .area => .{ .area = HTMLAreaElement.init(base) }, + .audio => .{ .audio = HTMLAudioElement.init(base) }, + .br => .{ .br = HTMLBRElement.init(base) }, + .base => .{ .base = HTMLBaseElement.init(base) }, + .body => .{ .body = HTMLBodyElement.init(base) }, + .button => .{ .button = HTMLButtonElement.init(base) }, + .canvas => .{ .canvas = HTMLCanvasElement.init(base) }, + .dl => .{ .dlist = HTMLDListElement.init(base) }, + .dialog => .{ .dialog = HTMLDialogElement.init(base) }, + .data => .{ .data = HTMLDataElement.init(base) }, + .div => .{ .div = HTMLDivElement.init(base) }, + .embed => .{ .embed = HTMLEmbedElement.init(base) }, + .fieldset => .{ .fieldset = HTMLFieldSetElement.init(base) }, + .form => .{ .form = HTMLFormElement.init(base) }, + .frameset => .{ .frameset = HTMLFrameSetElement.init(base) }, + .hr => .{ .hr = HTMLHRElement.init(base) }, + .head => .{ .head = HTMLHeadElement.init(base) }, + .h1, .h2, .h3, .h4, .h5, .h6 => .{ .heading = HTMLHeadingElement.init(base) }, + .html => .{ .html = HTMLHtmlElement.init(base) }, + .iframe => .{ .iframe = HTMLIFrameElement.init(base) }, + .img => .{ .img = HTMLImageElement.init(base) }, + .input => .{ .input = HTMLInputElement.init(base) }, + .li => .{ .li = HTMLLIElement.init(base) }, + .label => .{ .label = HTMLLabelElement.init(base) }, + .legend => .{ .legend = HTMLLegendElement.init(base) }, + .link => .{ .link = HTMLLinkElement.init(base) }, + .map => .{ .map = HTMLMapElement.init(base) }, + .meta => .{ .meta = HTMLMetaElement.init(base) }, + .meter => .{ .meter = HTMLMeterElement.init(base) }, + .ins, .del => .{ .mod = HTMLModElement.init(base) }, + .ol => .{ .olist = HTMLOListElement.init(base) }, + .object => .{ .object = HTMLObjectElement.init(base) }, + .optgroup => .{ .optgroup = HTMLOptGroupElement.init(base) }, + .option => .{ .option = HTMLOptionElement.init(base) }, + .output => .{ .output = HTMLOutputElement.init(base) }, + .p => .{ .paragraph = HTMLParagraphElement.init(base) }, + .picture => .{ .picture = HTMLPictureElement.init(base) }, + .pre => .{ .pre = HTMLPreElement.init(base) }, + .progress => .{ .progress = HTMLProgressElement.init(base) }, + .blockquote, .q => .{ .quote = HTMLQuoteElement.init(base) }, + .script => .{ .script = HTMLScriptElement.init(base) }, + .select => .{ .select = HTMLSelectElement.init(base) }, + .source => .{ .source = HTMLSourceElement.init(base) }, + .span => .{ .span = HTMLSpanElement.init(base) }, + .style => .{ .style = HTMLStyleElement.init(base) }, + .table => .{ .table = HTMLTableElement.init(base) }, + .caption => .{ .tablecaption = HTMLTableCaptionElement.init(base) }, + .th, .td => .{ .tablecell = HTMLTableCellElement.init(base) }, + .col => .{ .tablecol = HTMLTableColElement.init(base) }, + .tr => .{ .tablerow = HTMLTableRowElement.init(base) }, + .thead, .tbody, .tfoot => .{ .tablesection = HTMLTableSectionElement.init(base) }, + .template => .{ .template = HTMLTemplateElement.init(base) }, + .textarea => .{ .textarea = HTMLTextAreaElement.init(base) }, + .time => .{ .time = HTMLTimeElement.init(base) }, + .title => .{ .title = HTMLTitleElement.init(base) }, + .track => .{ .track = HTMLTrackElement.init(base) }, + .ul => .{ .ulist = HTMLUListElement.init(base) }, + .video => .{ .video = HTMLVideoElement.init(base) }, + .undef => .{ .unknown = HTMLUnknownElement.init(base) }, }; } diff --git a/src/parser.zig b/src/parser.zig index 20df1766..f018a230 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -7,6 +7,149 @@ const c = @cImport({ // 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 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); } +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 inline fn nodeName(node: *Node) [*c]const u8 { From fdafd96003971b68ba857de7b96c59989c6b1646 Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Thu, 18 May 2023 17:36:31 +0200 Subject: [PATCH 4/6] Move HTMLElements to generated union Signed-off-by: Francis Bouvier --- src/html/elements.zig | 313 +++++++++++++++++------------------------- 1 file changed, 128 insertions(+), 185 deletions(-) diff --git a/src/html/elements.zig b/src/html/elements.zig index a44973cd..039f8310 100644 --- a/src/html/elements.zig +++ b/src/html/elements.zig @@ -1,4 +1,5 @@ const parser = @import("../parser.zig"); +const generate = @import("../generate.zig"); const Element = @import("../dom/element.zig").Element; @@ -15,132 +16,74 @@ pub const HTMLElement = struct { } }; -const HTMLElementsTags = enum { - unknown, - anchor, - area, - audio, - br, - base, - body, - button, - canvas, - dlist, - dialog, - data, - div, - embed, - fieldset, - form, - frameset, - hr, - head, - heading, - html, - iframe, - img, - input, - li, - label, - legend, - link, - map, - meta, - meter, - mod, - olist, - object, - optgroup, - option, - output, - paragraph, - picture, - pre, - progress, - quote, - script, - select, - source, - span, - style, - table, - tablecaption, - tablecell, - tablecol, - tablerow, - tablesection, - template, - textarea, - time, - title, - track, - ulist, - video, -}; - -// 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 HTMLElementsTypes = .{ + HTMLUnknownElement, + HTMLAnchorElement, + HTMLAreaElement, + HTMLAudioElement, + HTMLBRElement, + HTMLBaseElement, + HTMLBodyElement, + HTMLButtonElement, + HTMLCanvasElement, + HTMLDListElement, + HTMLDialogElement, + HTMLDataElement, + HTMLDivElement, + HTMLEmbedElement, + HTMLFieldSetElement, + HTMLFormElement, + HTMLFrameSetElement, + HTMLHRElement, + HTMLHeadElement, + HTMLHeadingElement, + HTMLHtmlElement, + HTMLIFrameElement, + HTMLImageElement, + HTMLInputElement, + HTMLLIElement, + HTMLLabelElement, + HTMLLegendElement, + HTMLLinkElement, + HTMLMapElement, + HTMLMetaElement, + HTMLMeterElement, + HTMLModElement, + HTMLOListElement, + HTMLObjectElement, + HTMLOptGroupElement, + HTMLOptionElement, + HTMLOutputElement, + HTMLParagraphElement, + HTMLPictureElement, + HTMLPreElement, + HTMLProgressElement, + HTMLQuoteElement, + HTMLScriptElement, + HTMLSelectElement, + HTMLSourceElement, + HTMLSpanElement, + HTMLStyleElement, + HTMLTableElement, + HTMLTableCaptionElement, + HTMLTableCellElement, + HTMLTableColElement, + HTMLTableRowElement, + HTMLTableSectionElement, + HTMLTemplateElement, + HTMLTextAreaElement, + HTMLTimeElement, + HTMLTitleElement, + HTMLTrackElement, + HTMLUListElement, + HTMLVideoElement, }; +fn generateElements() generate.Union { + return generate.Union.compile(HTMLElementsTypes); +} +const HTMLElementsGenerated = generateElements(); +pub const HTMLElements = HTMLElementsGenerated._union; +pub const HTMLElementsTags = HTMLElementsGenerated._enum; // Deprecated HTMLElements in Chrome (2023/03/15) // HTMLContentelement @@ -765,65 +708,65 @@ pub const HTMLVideoElement = struct { pub fn ElementToHTMLElementInterface(base: *parser.Element) HTMLElements { const tag = parser.nodeTag(parser.elementNode(base)); return switch (tag) { - .a => .{ .anchor = HTMLAnchorElement.init(base) }, - .area => .{ .area = HTMLAreaElement.init(base) }, - .audio => .{ .audio = HTMLAudioElement.init(base) }, - .br => .{ .br = HTMLBRElement.init(base) }, - .base => .{ .base = HTMLBaseElement.init(base) }, - .body => .{ .body = HTMLBodyElement.init(base) }, - .button => .{ .button = HTMLButtonElement.init(base) }, - .canvas => .{ .canvas = HTMLCanvasElement.init(base) }, - .dl => .{ .dlist = HTMLDListElement.init(base) }, - .dialog => .{ .dialog = HTMLDialogElement.init(base) }, - .data => .{ .data = HTMLDataElement.init(base) }, - .div => .{ .div = HTMLDivElement.init(base) }, - .embed => .{ .embed = HTMLEmbedElement.init(base) }, - .fieldset => .{ .fieldset = HTMLFieldSetElement.init(base) }, - .form => .{ .form = HTMLFormElement.init(base) }, - .frameset => .{ .frameset = HTMLFrameSetElement.init(base) }, - .hr => .{ .hr = HTMLHRElement.init(base) }, - .head => .{ .head = HTMLHeadElement.init(base) }, - .h1, .h2, .h3, .h4, .h5, .h6 => .{ .heading = HTMLHeadingElement.init(base) }, - .html => .{ .html = HTMLHtmlElement.init(base) }, - .iframe => .{ .iframe = HTMLIFrameElement.init(base) }, - .img => .{ .img = HTMLImageElement.init(base) }, - .input => .{ .input = HTMLInputElement.init(base) }, - .li => .{ .li = HTMLLIElement.init(base) }, - .label => .{ .label = HTMLLabelElement.init(base) }, - .legend => .{ .legend = HTMLLegendElement.init(base) }, - .link => .{ .link = HTMLLinkElement.init(base) }, - .map => .{ .map = HTMLMapElement.init(base) }, - .meta => .{ .meta = HTMLMetaElement.init(base) }, - .meter => .{ .meter = HTMLMeterElement.init(base) }, - .ins, .del => .{ .mod = HTMLModElement.init(base) }, - .ol => .{ .olist = HTMLOListElement.init(base) }, - .object => .{ .object = HTMLObjectElement.init(base) }, - .optgroup => .{ .optgroup = HTMLOptGroupElement.init(base) }, - .option => .{ .option = HTMLOptionElement.init(base) }, - .output => .{ .output = HTMLOutputElement.init(base) }, - .p => .{ .paragraph = HTMLParagraphElement.init(base) }, - .picture => .{ .picture = HTMLPictureElement.init(base) }, - .pre => .{ .pre = HTMLPreElement.init(base) }, - .progress => .{ .progress = HTMLProgressElement.init(base) }, - .blockquote, .q => .{ .quote = HTMLQuoteElement.init(base) }, - .script => .{ .script = HTMLScriptElement.init(base) }, - .select => .{ .select = HTMLSelectElement.init(base) }, - .source => .{ .source = HTMLSourceElement.init(base) }, - .span => .{ .span = HTMLSpanElement.init(base) }, - .style => .{ .style = HTMLStyleElement.init(base) }, - .table => .{ .table = HTMLTableElement.init(base) }, - .caption => .{ .tablecaption = HTMLTableCaptionElement.init(base) }, - .th, .td => .{ .tablecell = HTMLTableCellElement.init(base) }, - .col => .{ .tablecol = HTMLTableColElement.init(base) }, - .tr => .{ .tablerow = HTMLTableRowElement.init(base) }, - .thead, .tbody, .tfoot => .{ .tablesection = HTMLTableSectionElement.init(base) }, - .template => .{ .template = HTMLTemplateElement.init(base) }, - .textarea => .{ .textarea = HTMLTextAreaElement.init(base) }, - .time => .{ .time = HTMLTimeElement.init(base) }, - .title => .{ .title = HTMLTitleElement.init(base) }, - .track => .{ .track = HTMLTrackElement.init(base) }, - .ul => .{ .ulist = HTMLUListElement.init(base) }, - .video => .{ .video = HTMLVideoElement.init(base) }, - .undef => .{ .unknown = HTMLUnknownElement.init(base) }, + .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) }, }; } From 76c8d8594c000271fd9709ef627cdffdfb80c203 Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Tue, 23 May 2023 15:23:09 +0200 Subject: [PATCH 5/6] Add generate function for Tuple Signed-off-by: Francis Bouvier --- src/dom.zig | 69 ++----------------- src/generate.zig | 149 ++++++++++++++++++++++++++++++++++++++++-- src/html/elements.zig | 7 +- 3 files changed, 149 insertions(+), 76 deletions(-) diff --git a/src/dom.zig b/src/dom.zig index 56e24f77..6d481fe3 100644 --- a/src/dom.zig +++ b/src/dom.zig @@ -1,3 +1,5 @@ +const generate = @import("generate.zig"); + const Console = @import("jsruntime").Console; // DOM @@ -12,7 +14,7 @@ pub const HTMLDocument = @import("html/document.zig").HTMLDocument; const E = @import("html/elements.zig"); // Interfaces -pub const Interfaces = .{ +const interfaces = .{ Console, // DOM @@ -23,69 +25,8 @@ pub const Interfaces = .{ // HTML HTMLDocument, - E.HTMLElement, E.HTMLMediaElement, - - // 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, + E.HTMLElementsTypes, }; +pub const Interfaces = generate.TupleInst(generate.TupleT(interfaces), interfaces); diff --git a/src/generate.zig b/src/generate.zig index a05e8a2e..27b6853b 100644 --- a/src/generate.zig +++ b/src/generate.zig @@ -6,6 +6,8 @@ fn fmtName(comptime T: type) []const u8 { 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, @@ -23,7 +25,7 @@ pub const Union = struct { const tuple_T = @TypeOf(tuple); const tuple_info = @typeInfo(tuple_T); if (tuple_info != .Struct or !tuple_info.Struct.is_tuple) { - return error.GenerateUnionArgNotTuple; + return error.GenerateArgNotTuple; } const tuple_members = tuple_info.Struct.fields; @@ -39,7 +41,7 @@ pub const Union = struct { } else if (member_info == .Struct) { members_nb += 1; } else { - return error.GenerateUnionMemberNotUnionOrStruct; + return error.GenerateMemberNotUnionOrStruct; } } @@ -64,7 +66,7 @@ pub const Union = struct { } else if (members_nb < 65536) { tag_type = u16; } else { - return error.GenerateUnionTooMuchMembers; + return error.GenerateTooMuchMembers; } // second iteration to generate tags @@ -100,7 +102,7 @@ pub const Union = struct { }; const enum_T = @Type(std.builtin.Type{ .Enum = enum_info }); - // third iteration to generate union + // third iteration to generate union type comptime var union_fields: [members_nb]std.builtin.Type.UnionField = undefined; done = 0; inline for (tuple_members) |member, i| { @@ -141,13 +143,123 @@ pub const Union = struct { } }; +fn itoa(comptime i: u8) ![]u8 { + comptime { + 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 + comptime 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{ - UnionArgNotTuple, - UnionMemberNotUnionOrStruct, - UnionTooMuchMembers, + GenerateArgNotTuple, + GenerateMemberNotUnionOrStruct, + GenerateMemberNotTupleOrStruct, + GenerateMemberTupleNotStruct, + GenerateTooMuchMembers, }; const Astruct = struct { @@ -200,4 +312,27 @@ pub fn tests() !void { 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", .{}); } diff --git a/src/html/elements.zig b/src/html/elements.zig index 039f8310..19a5f72e 100644 --- a/src/html/elements.zig +++ b/src/html/elements.zig @@ -16,7 +16,7 @@ pub const HTMLElement = struct { } }; -const HTMLElementsTypes = .{ +pub const HTMLElementsTypes = .{ HTMLUnknownElement, HTMLAnchorElement, HTMLAreaElement, @@ -78,10 +78,7 @@ const HTMLElementsTypes = .{ HTMLUListElement, HTMLVideoElement, }; -fn generateElements() generate.Union { - return generate.Union.compile(HTMLElementsTypes); -} -const HTMLElementsGenerated = generateElements(); +const HTMLElementsGenerated = generate.Union.compile(HTMLElementsTypes); pub const HTMLElements = HTMLElementsGenerated._union; pub const HTMLElementsTags = HTMLElementsGenerated._enum; From 4677968c8566402814d15a01f2b0a94a3131629d Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Tue, 23 May 2023 16:59:50 +0200 Subject: [PATCH 6/6] Remove unecessary comptime keyword in generate Signed-off-by: Francis Bouvier --- src/generate.zig | 46 +++++++++++++++++++++------------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/src/generate.zig b/src/generate.zig index 27b6853b..2c95b562 100644 --- a/src/generate.zig +++ b/src/generate.zig @@ -13,9 +13,7 @@ pub const Union = struct { _union: type, pub fn compile(comptime tuple: anytype) Union { - comptime { - return private_compile(tuple) catch @compileError("CompileUnion error"); - } + return private_compile(tuple) catch |err| @compileError(@errorName(err)); } fn private_compile(comptime tuple: anytype) !Union { @@ -31,8 +29,8 @@ pub const Union = struct { const tuple_members = tuple_info.Struct.fields; // first iteration to get the total number of members - comptime var members_nb = 0; - inline for (tuple_members) |member| { + 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) { @@ -46,7 +44,7 @@ pub const Union = struct { } // define the tag type regarding the members nb - comptime var tag_type: type = undefined; + var tag_type: type = undefined; if (members_nb < 3) { tag_type = u1; } else if (members_nb < 4) { @@ -70,14 +68,14 @@ pub const Union = struct { } // second iteration to generate tags - comptime var enum_fields: [members_nb]std.builtin.Type.EnumField = undefined; - comptime var done = 0; - inline for (tuple_members) |member| { + 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; - inline for (member_union.fields) |field| { + for (member_union.fields) |field| { enum_fields[done] = .{ .name = fmtName(field.field_type), .value = done, @@ -103,14 +101,14 @@ pub const Union = struct { const enum_T = @Type(std.builtin.Type{ .Enum = enum_info }); // third iteration to generate union type - comptime var union_fields: [members_nb]std.builtin.Type.UnionField = undefined; + var union_fields: [members_nb]std.builtin.Type.UnionField = undefined; done = 0; - inline for (tuple_members) |member, i| { + 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; - inline for (member_union.fields) |field| { + for (member_union.fields) |field| { union_fields[done] = .{ .name = fmtName(field.field_type), .field_type = field.field_type, @@ -144,18 +142,16 @@ pub const Union = struct { }; fn itoa(comptime i: u8) ![]u8 { - comptime { - 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}); + 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. @@ -172,7 +168,7 @@ pub fn TupleT(comptime tuple: anytype) type { const tuple_members = tuple_info.Struct.fields; // first iteration to get the total number of members - comptime var members_nb = 0; + var members_nb = 0; for (tuple_members) |member| { const member_T = @field(tuple, member.name); if (@TypeOf(member_T) == type) {