Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DOMException #81

Merged
merged 4 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/dom/dom.zig
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
const generate = @import("../generate.zig");

const DOMException = @import("exceptions.zig").DOMException;
const EventTarget = @import("event_target.zig").EventTarget;
const Nod = @import("node.zig");

pub const Interfaces = generate.Tuple(.{
DOMException,
EventTarget,
Nod.Node,
Nod.Interfaces,
Expand Down
3 changes: 3 additions & 0 deletions src/dom/event_target.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const parser = @import("../netsurf.zig");

const DOMException = @import("exceptions.zig").DOMException;

pub const EventTarget = struct {
pub const Self = parser.EventTarget;
pub const Exception = DOMException;
pub const mem_guarantied = true;
};
159 changes: 159 additions & 0 deletions src/dom/exceptions.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
const std = @import("std");
const allocPrint = std.fmt.allocPrint;

const jsruntime = @import("jsruntime");
const Case = jsruntime.test_utils.Case;
const checkCases = jsruntime.test_utils.checkCases;

const parser = @import("../netsurf.zig");

// https://webidl.spec.whatwg.org/#idl-DOMException
pub const DOMException = struct {
francisbouvier marked this conversation as resolved.
Show resolved Hide resolved
err: parser.DOMError,
str: []const u8,

pub const mem_guarantied = true;

pub const ErrorSet = parser.DOMError;

// static attributes
pub const _INDEX_SIZE_ERR = 1;
pub const _DOMSTRING_SIZE_ERR = 2;
pub const _HIERARCHY_REQUEST_ERR = 3;
pub const _WRONG_DOCUMENT_ERR = 4;
pub const _INVALID_CHARACTER_ERR = 5;
pub const _NO_DATA_ALLOWED_ERR = 6;
pub const _NO_MODIFICATION_ALLOWED_ERR = 7;
pub const _NOT_FOUND_ERR = 8;
pub const _NOT_SUPPORTED_ERR = 9;
pub const _INUSE_ATTRIBUTE_ERR = 10;
pub const _INVALID_STATE_ERR = 11;
pub const _SYNTAX_ERR = 12;
pub const _INVALID_MODIFICATION_ERR = 13;
pub const _NAMESPACE_ERR = 14;
pub const _INVALID_ACCESS_ERR = 15;
pub const _VALIDATION_ERR = 16;
pub const _TYPE_MISMATCH_ERR = 17;
krichprollsch marked this conversation as resolved.
Show resolved Hide resolved
pub const _SECURITY_ERR = 18;
pub const _NETWORK_ERR = 19;
pub const _ABORT_ERR = 20;
pub const _URL_MISMATCH_ERR = 21;
pub const _QUOTA_EXCEEDED_ERR = 22;
pub const _TIMEOUT_ERR = 23;
pub const _INVALID_NODE_TYPE_ERR = 24;
pub const _DATA_CLONE_ERR = 25;

// TODO: deinit
pub fn init(alloc: std.mem.Allocator, err: anyerror, callerName: []const u8) anyerror!DOMException {
const errCast = @as(parser.DOMError, @errSetCast(err));
const errName = DOMException.name(errCast);
const str = switch (errCast) {
error.HierarchyRequest => try allocPrint(
alloc,
"{s}: Failed to execute '{s}' on 'Node': The new child element contains the parent.",
.{ errName, callerName },
),
error.NoError => unreachable,
else => "", // TODO: implement other messages
};
return .{ .err = errCast, .str = str };
}

fn name(err: parser.DOMError) []const u8 {
return switch (err) {
error.IndexSize => "IndexSizeError",
error.StringSize => "StringSizeError",
error.HierarchyRequest => "HierarchyRequestError",
error.WrongDocument => "WrongDocumentError",
error.InvalidCharacter => "InvalidCharacterError",
error.NoDataAllowed => "NoDataAllowedError",
error.NoModificationAllowed => "NoModificationAllowedError",
error.NotFound => "NotFoundError",
error.NotSupported => "NotSupportedError",
error.InuseAttribute => "InuseAttributeError",
error.InvalidState => "InvalidStateError",
error.Syntax => "SyntaxError",
error.InvalidModification => "InvalidModificationError",
error.Namespace => "NamespaceError",
error.InvalidAccess => "InvalidAccessError",
error.Validation => "ValidationError",
error.TypeMismatch => "TypeMismatchError",
error.Security => "SecurityError",
error.Network => "NetworkError",
error.Abort => "AbortError",
error.URLismatch => "URLismatchError",
error.QuotaExceeded => "QuotaExceededError",
error.Timeout => "TimeoutError",
error.InvalidNodeType => "InvalidNodeTypeError",
error.DataClone => "DataCloneError",
error.NoError => unreachable,
francisbouvier marked this conversation as resolved.
Show resolved Hide resolved
};
}

// JS properties and methods

pub fn get_code(self: DOMException) u8 {
return switch (self.err) {
error.IndexSize => 1,
error.StringSize => 2,
error.HierarchyRequest => 3,
error.WrongDocument => 4,
error.InvalidCharacter => 5,
error.NoDataAllowed => 6,
error.NoModificationAllowed => 7,
error.NotFound => 8,
error.NotSupported => 9,
error.InuseAttribute => 10,
error.InvalidState => 11,
error.Syntax => 12,
error.InvalidModification => 13,
error.Namespace => 14,
error.InvalidAccess => 15,
error.Validation => 16,
error.TypeMismatch => 17,
error.Security => 18,
error.Network => 19,
error.Abort => 20,
error.URLismatch => 21,
error.QuotaExceeded => 22,
error.Timeout => 23,
error.InvalidNodeType => 24,
error.DataClone => 25,
error.NoError => unreachable,
francisbouvier marked this conversation as resolved.
Show resolved Hide resolved
};
}

pub fn get_name(self: DOMException) []const u8 {
return DOMException.name(self.err);
}

pub fn get_message(self: DOMException) []const u8 {
const errName = DOMException.name(self.err);
return self.str[errName.len + 2 ..];
}

pub fn _toString(self: DOMException) []const u8 {
return self.str;
}
};

// Tests
// -----

pub fn testExecFn(
_: std.mem.Allocator,
js_env: *jsruntime.Env,
comptime _: []jsruntime.API,
) !void {
const err = "Failed to execute 'appendChild' on 'Node': The new child element contains the parent.";
var cases = [_]Case{
.{ .src = "let content = document.getElementById('content')", .ex = "undefined" },
.{ .src = "let link = document.getElementById('link')", .ex = "undefined" },
// HierarchyRequestError
.{ .src = "var HierarchyRequestError; try {link.appendChild(content)} catch (error) {HierarchyRequestError = error} HierarchyRequestError.name", .ex = "HierarchyRequestError" },
.{ .src = "HierarchyRequestError.code", .ex = "3" },
.{ .src = "HierarchyRequestError.message", .ex = err },
.{ .src = "HierarchyRequestError.toString()", .ex = "HierarchyRequestError: " ++ err },
};
try checkCases(js_env, &cases);
}
4 changes: 2 additions & 2 deletions src/dom/node.zig
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,9 @@ pub const Node = struct {

// Methods

pub fn _appendChild(self: *parser.Node, child: *parser.Node) Union {
pub fn _appendChild(self: *parser.Node, child: *parser.Node) !Union {
// TODO: DocumentFragment special case
const res = parser.nodeAppendChild(self, child);
const res = try parser.nodeAppendChild(self, child);
return Node.toInterface(res);
}

Expand Down
62 changes: 60 additions & 2 deletions src/netsurf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,63 @@ pub const Tag = enum(u8) {
}
};

// DOMException

pub const DOMError = error{
NoError,
IndexSize,
StringSize,
HierarchyRequest,
WrongDocument,
InvalidCharacter,
NoDataAllowed,
NoModificationAllowed,
NotFound,
NotSupported,
InuseAttribute,
InvalidState,
Syntax,
InvalidModification,
Namespace,
InvalidAccess,
Validation,
TypeMismatch,
francisbouvier marked this conversation as resolved.
Show resolved Hide resolved
Security,
Network,
Abort,
URLismatch,
QuotaExceeded,
Timeout,
InvalidNodeType,
DataClone,
};

const DOMException = c.dom_exception;

fn DOMErr(except: DOMException) DOMError!void {
return switch (except) {
c.DOM_NO_ERR => return,
c.DOM_INDEX_SIZE_ERR => DOMError.IndexSize,
c.DOM_DOMSTRING_SIZE_ERR => DOMError.StringSize,
c.DOM_HIERARCHY_REQUEST_ERR => DOMError.HierarchyRequest,
c.DOM_WRONG_DOCUMENT_ERR => DOMError.WrongDocument,
c.DOM_INVALID_CHARACTER_ERR => DOMError.InvalidCharacter,
c.DOM_NO_DATA_ALLOWED_ERR => DOMError.NoDataAllowed,
c.DOM_NO_MODIFICATION_ALLOWED_ERR => DOMError.NoModificationAllowed,
c.DOM_NOT_FOUND_ERR => DOMError.NotFound,
c.DOM_NOT_SUPPORTED_ERR => DOMError.NotSupported,
c.DOM_INUSE_ATTRIBUTE_ERR => DOMError.InuseAttribute,
c.DOM_INVALID_STATE_ERR => DOMError.InvalidState,
c.DOM_SYNTAX_ERR => DOMError.Syntax,
c.DOM_INVALID_MODIFICATION_ERR => DOMError.InvalidModification,
c.DOM_NAMESPACE_ERR => DOMError.Namespace,
c.DOM_INVALID_ACCESS_ERR => DOMError.InvalidAccess,
c.DOM_VALIDATION_ERR => DOMError.Validation,
c.DOM_TYPE_MISMATCH_ERR => DOMError.TypeMismatch,
else => unreachable,
};
}

// EventTarget
pub const EventTarget = c.dom_event_target;

Expand Down Expand Up @@ -451,9 +508,10 @@ pub fn nodeSetTextContent(node: *Node, value: []const u8) void {
_ = nodeVtable(node).dom_node_set_text_content.?(node, s);
}

pub fn nodeAppendChild(node: *Node, child: *Node) *Node {
pub fn nodeAppendChild(node: *Node, child: *Node) DOMError!*Node {
var res: ?*Node = undefined;
_ = nodeVtable(node).dom_node_append_child.?(node, child, &res);
const err = nodeVtable(node).dom_node_append_child.?(node, child, &res);
try DOMErr(err);
return res.?;
}

Expand Down
2 changes: 2 additions & 0 deletions src/run_tests.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const nodeTestExecFn = @import("dom/node.zig").testExecFn;
const characterDataTestExecFn = @import("dom/character_data.zig").testExecFn;
const textTestExecFn = @import("dom/text.zig").testExecFn;
const HTMLCollectionTestExecFn = @import("dom/html_collection.zig").testExecFn;
const DOMExceptionTestExecFn = @import("dom/exceptions.zig").testExecFn;

var doc: *parser.DocumentHTML = undefined;

Expand Down Expand Up @@ -53,6 +54,7 @@ fn testsAllExecFn(
characterDataTestExecFn,
textTestExecFn,
HTMLCollectionTestExecFn,
DOMExceptionTestExecFn,
};

inline for (testFns) |testFn| {
Expand Down
Loading