diff options
author | Ali Mohammad Pur <ali.mpfard@gmail.com> | 2021-06-27 00:17:13 +0430 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-06-27 12:49:49 +0100 |
commit | fd72597999b61843a176d1e8a8b0d15a68d69e1e (patch) | |
tree | a6f760beb69ec2c66e8b7880a3b6f17d2478f486 /Userland | |
parent | bda19a9ff3ae8e935562f8a5a95f5ba0ef585b84 (diff) | |
download | serenity-fd72597999b61843a176d1e8a8b0d15a68d69e1e.zip |
LibWeb: Make ExceptionOr capable of holding all error types in the spec
The WebIDL spec specifies a few "simple" exception types in addition to
the DOMException type, let's support all of those.
This allows functions returning ExceptionOr<T> to throw regular
javascript exceptions (as limited by the webidl spec) by returning a
`DOM::SimpleException { DOM::SimpleExceptionType::T, "error message" }`
which is pretty damn cool :^)
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h | 10 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Document.cpp | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/ExceptionOr.h | 96 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Node.cpp | 2 |
4 files changed, 77 insertions, 35 deletions
diff --git a/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h b/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h index 94d5bf62f1..eb089070af 100644 --- a/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h +++ b/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h @@ -24,7 +24,10 @@ template<typename T> ALWAYS_INLINE bool throw_dom_exception(JS::VM& vm, JS::GlobalObject& global_object, DOM::ExceptionOr<T>& result) { if (result.is_exception()) { - vm.throw_exception(global_object, DOMExceptionWrapper::create(global_object, const_cast<DOM::DOMException&>(result.exception()))); + result.materialized_exception(global_object) + .visit( + [&](NonnullRefPtr<DOM::DOMException> dom_exception) { vm.throw_exception(global_object, DOMExceptionWrapper::create(global_object, move(dom_exception))); }, + [&](auto* js_exception) { vm.throw_exception(global_object, js_exception); }); return true; } return false; @@ -48,6 +51,11 @@ struct ExtractExceptionOrValueType<void> { }; template<> +struct ExtractExceptionOrValueType<DOM::ExceptionOr<Empty>> { + using Type = JS::Value; +}; + +template<> struct ExtractExceptionOrValueType<DOM::ExceptionOr<void>> { using Type = JS::Value; }; diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 68824b541a..660828084f 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -224,7 +224,7 @@ ExceptionOr<void> Document::set_body(HTML::HTMLElement& new_body) if (existing_body) { auto replace_result = existing_body->parent()->replace_child(new_body, *existing_body); if (replace_result.is_exception()) - return NonnullRefPtr<DOMException>(replace_result.exception()); + return replace_result.exception(); return {}; } @@ -234,7 +234,7 @@ ExceptionOr<void> Document::set_body(HTML::HTMLElement& new_body) auto append_result = document_element->append_child(new_body); if (append_result.is_exception()) - return NonnullRefPtr<DOMException>(append_result.exception()); + return append_result.exception(); return {}; } diff --git a/Userland/Libraries/LibWeb/DOM/ExceptionOr.h b/Userland/Libraries/LibWeb/DOM/ExceptionOr.h index df1e32cee7..5b5da29b83 100644 --- a/Userland/Libraries/LibWeb/DOM/ExceptionOr.h +++ b/Userland/Libraries/LibWeb/DOM/ExceptionOr.h @@ -13,9 +13,29 @@ namespace Web::DOM { +#define ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) \ + E(EvalError) \ + E(RangeError) \ + E(ReferenceError) \ + E(TypeError) \ + E(URIError) + +#define E(x) x, +enum class SimpleExceptionType { + ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) +}; +#undef E + +struct SimpleException { + SimpleExceptionType type; + String message; +}; + template<typename ValueType> class ExceptionOr { public: + ExceptionOr() requires(IsSame<ValueType, Empty>) = default; + ExceptionOr(const ValueType& result) : m_result(result) { @@ -26,8 +46,18 @@ public: { } - ExceptionOr(const NonnullRefPtr<DOMException> exception) - : m_exception(exception) + ExceptionOr(NonnullRefPtr<DOMException> exception) + : m_exception(move(exception)) + { + } + + ExceptionOr(SimpleException exception) + : m_exception(move(exception)) + { + } + + ExceptionOr(Variant<SimpleException, NonnullRefPtr<DOMException>> exception) + : m_exception(move(exception).template downcast<Empty, SimpleException, NonnullRefPtr<DOMException>>()) { } @@ -35,56 +65,60 @@ public: ExceptionOr(const ExceptionOr& other) = default; ~ExceptionOr() = default; - ValueType& value() + ValueType& value() requires(!IsSame<ValueType, Empty>) { return m_result.value(); } - ValueType release_value() + ValueType release_value() requires(!IsSame<ValueType, Empty>) { return m_result.release_value(); } - const DOMException& exception() const + Variant<SimpleException, NonnullRefPtr<DOMException>> exception() const { - return *m_exception; + return m_exception.template downcast<SimpleException, NonnullRefPtr<DOMException>>(); + } + + auto materialized_exception(JS::GlobalObject& global_object) const + { +#define E(x) JS::x*, + using ResultType = Variant<ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) NonnullRefPtr<DOMException>>; +#undef E + + return m_exception.visit( + [&](SimpleException& exception) -> ResultType { + switch (exception.type) { +#define E(x) \ + case SimpleExceptionType::x: \ + return JS::x::create(global_object, exception.message); + + ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) + +#undef E + default: + VERIFY_NOT_REACHED(); + } + }, + [&](NonnullRefPtr<DOMException> const& exception) -> ResultType { return exception; }, + [](Empty) -> ResultType { VERIFY_NOT_REACHED(); }); } bool is_exception() const { - return m_exception; + return !m_exception.template has<Empty>(); } private: Optional<ValueType> m_result; - RefPtr<DOMException> m_exception; + // https://heycam.github.io/webidl/#idl-exceptions + Variant<Empty, SimpleException, NonnullRefPtr<DOMException>> m_exception { Empty {} }; }; template<> -class ExceptionOr<void> { +class ExceptionOr<void> : public ExceptionOr<Empty> { public: - ExceptionOr(const NonnullRefPtr<DOMException> exception) - : m_exception(exception) - { - } - - ExceptionOr() = default; - ExceptionOr(ExceptionOr&& other) = default; - ExceptionOr(const ExceptionOr& other) = default; - ~ExceptionOr() = default; - - const DOMException& exception() const - { - return *m_exception; - } - - bool is_exception() const - { - return m_exception; - } - -private: - RefPtr<DOMException> m_exception; + using ExceptionOr<Empty>::ExceptionOr; }; } diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index 058cd1f459..aacf3cc5b5 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -267,7 +267,7 @@ ExceptionOr<NonnullRefPtr<Node>> Node::pre_insert(NonnullRefPtr<Node> node, RefP { auto validity_result = ensure_pre_insertion_validity(node, child); if (validity_result.is_exception()) - return NonnullRefPtr<DOMException>(validity_result.exception()); + return validity_result.exception(); auto reference_child = child; if (reference_child == node) |