diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp index 58cc9d0ef2..b49cb3a0a7 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp @@ -1414,21 +1414,14 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@) if (is_static_function == StaticFunction::No) { function_generator.append(R"~~~( - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl->@function.cpp_name@(@.arguments@); }); + [[maybe_unused]] auto retval = TRY(throw_dom_exception_if_needed(global_object, [&] { return impl->@function.cpp_name@(@.arguments@); })); )~~~"); } else { function_generator.append(R"~~~( - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return @interface_fully_qualified_name@::@function.cpp_name@(@.arguments@); }); + [[maybe_unused]] auto retval = TRY(throw_dom_exception_if_needed(global_object, [&] { return @interface_fully_qualified_name@::@function.cpp_name@(@.arguments@); })); )~~~"); } - function_generator.append(R"~~~( - if (should_return_empty(result)) - return JS::throw_completion(vm.exception()->value()); - - [[maybe_unused]] auto retval = result.release_value(); -)~~~"); - generate_return_statement(generator, *function.return_type); function_generator.append(R"~~~( @@ -1558,8 +1551,8 @@ private: if (interface.is_legacy_platform_object()) { generator.append(R"~~~( bool is_named_property_exposed_on_object(JS::PropertyKey const&) const; - Optional legacy_platform_object_get_own_property_for_get_own_property_slot(JS::PropertyKey const&) const; - Optional legacy_platform_object_get_own_property_for_set_slot(JS::PropertyKey const&) const; + JS::ThrowCompletionOr> legacy_platform_object_get_own_property_for_get_own_property_slot(JS::PropertyKey const&) const; + JS::ThrowCompletionOr> legacy_platform_object_get_own_property_for_set_slot(JS::PropertyKey const&) const; )~~~"); } @@ -1807,12 +1800,11 @@ bool @class_name@::is_named_property_exposed_on_object(JS::PropertyKey const& pr get_own_property_generator.set("internal_method"sv, for_which_internal_method); get_own_property_generator.append(R"~~~( -Optional @class_name@::legacy_platform_object_get_own_property_for_@internal_method@_slot(JS::PropertyKey const& property_name) const +JS::ThrowCompletionOr> @class_name@::legacy_platform_object_get_own_property_for_@internal_method@_slot(JS::PropertyKey const& property_name) const { )~~~"); get_own_property_generator.append(R"~~~( - [[maybe_unused]] auto& vm = this->vm(); [[maybe_unused]] auto& global_object = this->global_object(); )~~~"); @@ -1834,7 +1826,7 @@ Optional @class_name@::legacy_platform_object_get_own_pr // 3. If operation was defined without an identifier, then set value to the result of performing the steps listed in the interface description to determine the value of an indexed property with index as the index. if (interface.indexed_property_getter->name.is_empty()) { get_own_property_generator.append(R"~~~( - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl().determine_value_of_indexed_property(index); }); + auto value = TRY(throw_dom_exception_if_needed(global_object, [&] { return impl().determine_value_of_indexed_property(index); })); )~~~"); } @@ -1845,16 +1837,11 @@ Optional @class_name@::legacy_platform_object_get_own_pr function_scoped_generator.set("function.cpp_name", make_input_acceptable_cpp(interface.indexed_property_getter->name.to_snakecase())); function_scoped_generator.append(R"~~~( - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl().@function.cpp_name@(index); }); + auto value = TRY(throw_dom_exception_if_needed(global_object, [&] { return impl().@function.cpp_name@(index); })); )~~~"); } get_own_property_generator.append(R"~~~( - if (should_return_empty(result)) - return {}; - - auto value = result.release_value(); - // 5. Let desc be a newly created Property Descriptor with no fields. JS::PropertyDescriptor descriptor; @@ -1885,7 +1872,7 @@ Optional @class_name@::legacy_platform_object_get_own_pr // 3. Set ignoreNamedProps to true. // NOTE: To reduce complexity of WrapperGenerator, this just returns early instead of keeping track of another variable. - return TRY_OR_DISCARD(Object::internal_get_own_property(property_name)); + return TRY(Object::internal_get_own_property(property_name)); } )~~~"); } @@ -1905,7 +1892,7 @@ Optional @class_name@::legacy_platform_object_get_own_pr // 3. If operation was defined without an identifier, then set value to the result of performing the steps listed in the interface description to determine the value of a named property with P as the name. if (interface.named_property_getter->name.is_empty()) { get_own_property_generator.append(R"~~~( - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl().determine_value_of_named_property(property_name_string); }); + auto value = TRY(throw_dom_exception_if_needed(global_object, [&] { return impl().determine_value_of_named_property(property_name_string); })); )~~~"); } @@ -1915,16 +1902,11 @@ Optional @class_name@::legacy_platform_object_get_own_pr function_scoped_generator.set("function.cpp_name", make_input_acceptable_cpp(interface.named_property_getter->name.to_snakecase())); function_scoped_generator.append(R"~~~( - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl().@function.cpp_name@(property_name_string); }); + auto value = TRY(throw_dom_exception_if_needed(global_object, [&] { return impl().@function.cpp_name@(property_name_string); })); )~~~"); } get_own_property_generator.append(R"~~~( - if (should_return_empty(result)) - return {}; - - auto value = result.release_value(); - // 5. Let desc be a newly created Property Descriptor with no fields. JS::PropertyDescriptor descriptor; @@ -1966,7 +1948,7 @@ Optional @class_name@::legacy_platform_object_get_own_pr // 3. Return OrdinaryGetOwnProperty(O, P). get_own_property_generator.append(R"~~~( - return TRY_OR_DISCARD(Object::internal_get_own_property(property_name)); + return TRY(Object::internal_get_own_property(property_name)); } )~~~"); }; @@ -1985,8 +1967,6 @@ Optional @class_name@::legacy_platform_object_get_own_pr scoped_generator.append(R"~~~( static JS::ThrowCompletionOr invoke_named_property_setter(JS::GlobalObject& global_object, @fully_qualified_name@& impl, String const& property_name, JS::Value value) { - auto& vm = global_object.vm(); - // 1. Let creating be true if P is not a supported property name, and false otherwise. // NOTE: This is in it's own variable to enforce the type. // FIXME: Can this throw? @@ -2005,14 +1985,10 @@ static JS::ThrowCompletionOr invoke_named_property_setter(JS::GlobalObject scoped_generator.append(R"~~~( if (creating) { // 5.1. If creating is true, then perform the steps listed in the interface description to set the value of a new named property with P as the name and value as the value. - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { impl.set_value_of_new_named_property(property_name, converted_value); }); - if (should_return_empty(result)) - return JS::throw_completion(vm.exception()->value()); + TRY(throw_dom_exception_if_needed(global_object, [&] { impl.set_value_of_new_named_property(property_name, converted_value); })); } else { // 5.2 Otherwise, creating is false. Perform the steps listed in the interface description to set the value of an existing named property with P as the name and value as the value. - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { impl.set_value_of_existing_named_property(property_name, converted_value); }); - if (should_return_empty(result)) - return JS::throw_completion(vm.exception()->value()); + TRY(throw_dom_exception_if_needed(global_object, [&] { impl.set_value_of_existing_named_property(property_name, converted_value); })); } )~~~"); } else { @@ -2022,9 +1998,7 @@ static JS::ThrowCompletionOr invoke_named_property_setter(JS::GlobalObject function_scoped_generator.set("function.cpp_name", make_input_acceptable_cpp(interface.named_property_setter->name.to_snakecase())); function_scoped_generator.append(R"~~~( - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { impl.@function.cpp_name@(property_name, converted_value); }); - if (should_return_empty(result)) - return JS::throw_completion(vm.exception()->value()); + TRY(throw_dom_exception_if_needed(global_object, [&] { impl.@function.cpp_name@(property_name, converted_value); })); )~~~"); } @@ -2042,8 +2016,6 @@ static JS::ThrowCompletionOr invoke_named_property_setter(JS::GlobalObject scoped_generator.append(R"~~~( static JS::ThrowCompletionOr invoke_indexed_property_setter(JS::GlobalObject& global_object, @fully_qualified_name@& impl, JS::PropertyKey const& property_name, JS::Value value) { - auto& vm = global_object.vm(); - // 1. Let index be the result of calling ToUint32(P). u32 index = property_name.as_number(); @@ -2064,14 +2036,10 @@ static JS::ThrowCompletionOr invoke_indexed_property_setter(JS::GlobalObje scoped_generator.append(R"~~~( if (creating) { // 6.1 If creating is true, then perform the steps listed in the interface description to set the value of a new indexed property with index as the index and value as the value. - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { impl.set_value_of_new_indexed_property(index, converted_value); }); - if (should_return_empty(result)) - return JS::throw_completion(vm.exception()->value()); + TRY(throw_dom_exception_if_needed(global_object, [&] { impl.set_value_of_new_indexed_property(index, converted_value); })); } else { // 6.2 Otherwise, creating is false. Perform the steps listed in the interface description to set the value of an existing indexed property with index as the index and value as the value. - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { impl.set_value_of_existing_indexed_property(index, converted_value); }); - if (should_return_empty(result)) - return JS::throw_completion(vm.exception()->value()); + TRY(throw_dom_exception_if_needed(global_object, [&] { impl.set_value_of_existing_indexed_property(index, converted_value); })); } )~~~"); } else { @@ -2081,9 +2049,7 @@ static JS::ThrowCompletionOr invoke_indexed_property_setter(JS::GlobalObje function_scoped_generator.set("function.cpp_name", make_input_acceptable_cpp(interface.indexed_property_setter->name.to_snakecase())); function_scoped_generator.append(R"~~~( - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { impl.@function.cpp_name@(index, converted_value); }); - if (should_return_empty(result)) - return JS::throw_completion(vm.exception()->value()); + TRY(throw_dom_exception_if_needed(global_object, [&] { impl.@function.cpp_name@(index, converted_value); })); )~~~"); } @@ -2099,7 +2065,7 @@ static JS::ThrowCompletionOr invoke_indexed_property_setter(JS::GlobalObje JS::ThrowCompletionOr> @class_name@::internal_get_own_property(JS::PropertyKey const& property_name) const { // 1. Return LegacyPlatformObjectGetOwnProperty(O, P, false). - return legacy_platform_object_get_own_property_for_get_own_property_slot(property_name); + return TRY(legacy_platform_object_get_own_property_for_get_own_property_slot(property_name)); } )~~~"); @@ -2107,7 +2073,6 @@ JS::ThrowCompletionOr> @class_name@::internal_g scoped_generator.append(R"~~~( JS::ThrowCompletionOr @class_name@::internal_set(JS::PropertyKey const& property_name, JS::Value value, JS::Value receiver) { - auto& vm = this->vm(); [[maybe_unused]] auto& global_object = this->global_object(); )~~~"); @@ -2153,9 +2118,7 @@ JS::ThrowCompletionOr @class_name@::internal_set(JS::PropertyKey const& pr scoped_generator.append(R"~~~( // 2. Let ownDesc be LegacyPlatformObjectGetOwnProperty(O, P, true). - auto own_descriptor = legacy_platform_object_get_own_property_for_set_slot(property_name); - if (auto* exception = vm.exception()) - return JS::throw_completion(exception->value()); + auto own_descriptor = TRY(legacy_platform_object_get_own_property_for_set_slot(property_name)); // 3. Perform ? OrdinarySetWithOwnDescriptor(O, P, V, Receiver, ownDesc). // NOTE: The spec says "perform" instead of "return", meaning nothing will be returned on this path according to the spec, which isn't possible to do. @@ -2288,7 +2251,6 @@ JS::ThrowCompletionOr @class_name@::internal_define_own_property(JS::Prope scoped_generator.append(R"~~~( JS::ThrowCompletionOr @class_name@::internal_delete(JS::PropertyKey const& property_name) { - [[maybe_unused]] auto& vm = this->vm(); auto& global_object = this->global_object(); )~~~"); @@ -2335,12 +2297,7 @@ JS::ThrowCompletionOr @class_name@::internal_delete(JS::PropertyKey const& if (interface.named_property_deleter->name.is_empty()) { scoped_generator.append(R"~~~( // 1. Perform the steps listed in the interface description to delete an existing named property with P as the name. - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl().delete_existing_named_property(property_name_string); }); - // FIXME: Make this nicer for ThrowCompletionOr. - if (should_return_empty(result)) - return JS::throw_completion(vm.exception()->value()); - - bool succeeded = result.release_value(); + bool succeeded = TRY(throw_dom_exception_if_needed(global_object, [&] { return impl().delete_existing_named_property(property_name_string); })); // 2. If the steps indicated that the deletion failed, then return false. if (!succeeded) @@ -2353,17 +2310,13 @@ JS::ThrowCompletionOr @class_name@::internal_delete(JS::PropertyKey const& function_scoped_generator.append(R"~~~( // 1. Perform method steps of operation with O as this and « P » as the argument values. - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl().@function.cpp_name@(property_name_string); }); - // FIXME: Make this nicer for ThrowCompletionOr. - if (should_return_empty(result)) - return JS::throw_completion(vm.exception()->value()); + [[maybe_unused]] auto result = TRY(throw_dom_exception_if_needed(global_object, [&] { return impl().@function.cpp_name@(property_name_string); })); )~~~"); // 2. If operation was declared with a return type of boolean and the steps returned false, then return false. if (interface.named_property_deleter->return_type->name == "boolean") { function_scoped_generator.append(R"~~~( - bool succeeded = result.release_value(); - if (!succeeded) + if (!result) return false; )~~~"); } @@ -2632,17 +2585,15 @@ JS::ThrowCompletionOr @constructor_class@::construct(FunctionObject generator.set(".constructor_arguments", arguments_builder.string_view()); generator.append(R"~~~( - auto impl = throw_dom_exception_if_needed(vm, global_object, [&] { return @fully_qualified_name@::create_with_global_object(window, @.constructor_arguments@); }); + auto impl = TRY(throw_dom_exception_if_needed(global_object, [&] { return @fully_qualified_name@::create_with_global_object(window, @.constructor_arguments@); })); )~~~"); } else { generator.append(R"~~~( - auto impl = throw_dom_exception_if_needed(vm, global_object, [&] { return @fully_qualified_name@::create_with_global_object(window); }); + auto impl = TRY(throw_dom_exception_if_needed(global_object, [&] { return @fully_qualified_name@::create_with_global_object(window); })); )~~~"); } generator.append(R"~~~( - if (should_return_empty(impl)) - return JS::throw_completion(vm.exception()->value()); - return wrap(global_object, *impl.release_value()); + return wrap(global_object, *impl); )~~~"); } else { // Multiple constructor overloads - can't do that yet. @@ -3197,10 +3148,7 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.setter_callback@) } } else { attribute_generator.append(R"~~~( - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl->set_@attribute.name:snakecase@(cpp_value); }); - - if (should_return_empty(result)) - return JS::throw_completion(vm.exception()->value()); + TRY(throw_dom_exception_if_needed(global_object, [&] { return impl->set_@attribute.name:snakecase@(cpp_value); })); )~~~"); } @@ -3234,12 +3182,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::to_string) )~~~"); } else { stringifier_generator.append(R"~~~( - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl->to_string(); }); - - if (should_return_empty(result)) - return JS::throw_completion(vm.exception()->value()); - - auto retval = result.release_value(); + auto retval = TRY(throw_dom_exception_if_needed(global_object, [&] { return impl->to_string(); })); )~~~"); } stringifier_generator.append(R"~~~( @@ -3583,12 +3526,7 @@ static JS::ThrowCompletionOr<@fully_qualified_name@*> impl_from(JS::VM& vm, JS:: JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::next) { auto* impl = TRY(impl_from(vm, global_object)); - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { return impl->next(); }); - - if (should_return_empty(result)) - return JS::throw_completion(vm.exception()->value()); - - return result.release_value(); + return TRY(throw_dom_exception_if_needed(global_object, [&] { return impl->next(); })); } } // namespace Web::Bindings diff --git a/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h b/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h index eb089070af..2fa51c1f11 100644 --- a/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h +++ b/Userland/Libraries/LibWeb/Bindings/ExceptionOrUtils.h @@ -20,19 +20,6 @@ constexpr bool IsExceptionOr = false; template constexpr bool IsExceptionOr> = true; -template -ALWAYS_INLINE bool throw_dom_exception(JS::VM& vm, JS::GlobalObject& global_object, DOM::ExceptionOr& result) -{ - if (result.is_exception()) { - result.materialized_exception(global_object) - .visit( - [&](NonnullRefPtr 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; -} - namespace Detail { template @@ -60,22 +47,47 @@ struct ExtractExceptionOrValueType> { using Type = JS::Value; }; +ALWAYS_INLINE JS::Completion dom_exception_to_throw_completion(auto&& global_object, auto&& exception) +{ + auto& vm = global_object.vm(); + + return exception.visit( + [&](DOM::SimpleException const& exception) { + switch (exception.type) { +#define E(x) \ + case DOM::SimpleExceptionType::x: \ + return vm.template throw_completion(global_object, exception.message); + + ENUMERATE_SIMPLE_WEBIDL_EXCEPTION_TYPES(E) + +#undef E + default: + VERIFY_NOT_REACHED(); + } + }, + [&](NonnullRefPtr exception) { + return vm.template throw_completion(global_object, move(exception)); + }); +} + } template using ExtractExceptionOrValueType = typename Detail::ExtractExceptionOrValueType::Type; // Return type depends on the return type of 'fn' (when invoked with no args): -// void or ExceptionOr: Optional, always returns JS::js_undefined() -// ExceptionOr: Optional -// T: Optional +// void or ExceptionOr: JS::ThrowCompletionOr, always returns JS::js_undefined() +// ExceptionOr: JS::ThrowCompletionOr +// T: JS::ThrowCompletionOr template()()), typename Ret = Conditional && !IsVoid, T, ExtractExceptionOrValueType>> -Optional throw_dom_exception_if_needed(auto&& vm, auto&& global_object, F&& fn) +JS::ThrowCompletionOr throw_dom_exception_if_needed(auto&& global_object, F&& fn) { if constexpr (IsExceptionOr) { auto&& result = fn(); - if (throw_dom_exception(vm, global_object, result)) - return {}; + + if (result.is_exception()) + return Detail::dom_exception_to_throw_completion(global_object, result.exception()); + if constexpr (requires(T v) { v.value(); }) return result.value(); else @@ -88,12 +100,4 @@ Optional throw_dom_exception_if_needed(auto&& vm, auto&& global_object, F&& } } -template -bool should_return_empty(const Optional& value) -{ - if constexpr (IsSame) - return !value.has_value() || value.value().is_empty(); - return !value.has_value(); -} - } diff --git a/Userland/Libraries/LibWeb/Bindings/WindowObject.cpp b/Userland/Libraries/LibWeb/Bindings/WindowObject.cpp index 5aabced3bb..e23e69851c 100644 --- a/Userland/Libraries/LibWeb/Bindings/WindowObject.cpp +++ b/Userland/Libraries/LibWeb/Bindings/WindowObject.cpp @@ -636,33 +636,31 @@ JS_DEFINE_NATIVE_FUNCTION(WindowObject::screen_y_getter) return JS::Value(impl->screen_y()); } -#define __ENUMERATE(attribute, event_name) \ - JS_DEFINE_NATIVE_FUNCTION(WindowObject::attribute##_getter) \ - { \ - auto* impl = TRY(impl_from(vm, global_object)); \ - auto retval = impl->attribute(); \ - if (retval.callback.is_null()) \ - return JS::js_null(); \ - return retval.callback.cell(); \ - } \ - JS_DEFINE_NATIVE_FUNCTION(WindowObject::attribute##_setter) \ - { \ - auto* impl = TRY(impl_from(vm, global_object)); \ - auto value = vm.argument(0); \ - HTML::EventHandler cpp_value; \ - if (value.is_function()) { \ - cpp_value.callback = JS::make_handle(&value.as_function()); \ - } else if (value.is_string()) { \ - cpp_value.string = value.as_string().string(); \ - } else { \ - return JS::js_undefined(); \ - } \ - auto result = throw_dom_exception_if_needed(vm, global_object, [&] { \ - return impl->set_##attribute(cpp_value); \ - }); \ - if (should_return_empty(result)) \ - return JS::throw_completion(vm.exception()->value()); \ - return JS::js_undefined(); \ +#define __ENUMERATE(attribute, event_name) \ + JS_DEFINE_NATIVE_FUNCTION(WindowObject::attribute##_getter) \ + { \ + auto* impl = TRY(impl_from(vm, global_object)); \ + auto retval = impl->attribute(); \ + if (retval.callback.is_null()) \ + return JS::js_null(); \ + return retval.callback.cell(); \ + } \ + JS_DEFINE_NATIVE_FUNCTION(WindowObject::attribute##_setter) \ + { \ + auto* impl = TRY(impl_from(vm, global_object)); \ + auto value = vm.argument(0); \ + HTML::EventHandler cpp_value; \ + if (value.is_function()) { \ + cpp_value.callback = JS::make_handle(&value.as_function()); \ + } else if (value.is_string()) { \ + cpp_value.string = value.as_string().string(); \ + } else { \ + return JS::js_undefined(); \ + } \ + TRY(throw_dom_exception_if_needed(global_object, [&] { \ + return impl->set_##attribute(cpp_value); \ + })); \ + return JS::js_undefined(); \ } ENUMERATE_GLOBAL_EVENT_HANDLERS(__ENUMERATE) #undef __ENUMERATE diff --git a/Userland/Libraries/LibWeb/DOM/ExceptionOr.h b/Userland/Libraries/LibWeb/DOM/ExceptionOr.h index f3221dec59..ec889a3337 100644 --- a/Userland/Libraries/LibWeb/DOM/ExceptionOr.h +++ b/Userland/Libraries/LibWeb/DOM/ExceptionOr.h @@ -80,30 +80,6 @@ public: return m_exception.template downcast>(); } - auto materialized_exception(JS::GlobalObject& global_object) const - { -#define E(x) JS::x*, - using ResultType = Variant>; -#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 const& exception) -> ResultType { return exception; }, - [](Empty) -> ResultType { VERIFY_NOT_REACHED(); }); - } - bool is_exception() const { return !m_exception.template has();