diff options
5 files changed, 42 insertions, 29 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp index 5fa9080b0b..57e837c819 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -52,31 +52,47 @@ size_t length_of_array_like(GlobalObject& global_object, Object const& object) } // 7.3.19 CreateListFromArrayLike ( obj [ , elementTypes ] ), https://tc39.es/ecma262/#sec-createlistfromarraylike -MarkedValueList create_list_from_array_like(GlobalObject& global_object, Value value, Function<void(Value)> check_value) +ThrowCompletionOr<MarkedValueList> create_list_from_array_like(GlobalObject& global_object, Value value, Function<ThrowCompletionOr<void>(Value)> check_value) { auto& vm = global_object.vm(); auto& heap = global_object.heap(); - if (!value.is_object()) { - vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, value.to_string_without_side_effects()); - return MarkedValueList { heap }; - } + + // 1. If elementTypes is not present, set elementTypes to « Undefined, Null, Boolean, String, Symbol, Number, BigInt, Object ». + + // 2. If Type(obj) is not Object, throw a TypeError exception. + if (!value.is_object()) + return vm.throw_completion<TypeError>(global_object, ErrorType::NotAnObject, value.to_string_without_side_effects()); + auto& array_like = value.as_object(); + + // 3. Let len be ? LengthOfArrayLike(obj). auto length = length_of_array_like(global_object, array_like); - if (vm.exception()) - return MarkedValueList { heap }; + if (auto* exception = vm.exception()) + return throw_completion(exception->value()); + + // 4. Let list be a new empty List. auto list = MarkedValueList { heap }; + + // 5. Let index be 0. + // 6. Repeat, while index < len, for (size_t i = 0; i < length; ++i) { + // a. Let indexName be ! ToString(𝔽(index)). auto index_name = String::number(i); + + // b. Let next be ? Get(obj, indexName). auto next = array_like.get(index_name); - if (vm.exception()) - return MarkedValueList { heap }; - if (check_value) { - check_value(next); - if (vm.exception()) - return MarkedValueList { heap }; - } + if (auto* exception = vm.exception()) + return throw_completion(exception->value()); + + // c. If Type(next) is not an element of elementTypes, throw a TypeError exception. + if (check_value) + TRY(check_value(next)); + + // d. Append next as the last element of list. list.append(next); } + + // 7. Return list. return list; } diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.h b/Userland/Libraries/LibJS/Runtime/AbstractOperations.h index 6fb61bad9f..acdae60347 100644 --- a/Userland/Libraries/LibJS/Runtime/AbstractOperations.h +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.h @@ -21,7 +21,7 @@ Object* get_super_constructor(VM&); Reference make_super_property_reference(GlobalObject&, Value actual_this, StringOrSymbol const& property_key, bool strict); ThrowCompletionOr<Value> require_object_coercible(GlobalObject&, Value); size_t length_of_array_like(GlobalObject&, Object const&); -MarkedValueList create_list_from_array_like(GlobalObject&, Value, Function<void(Value)> = {}); +ThrowCompletionOr<MarkedValueList> create_list_from_array_like(GlobalObject&, Value, Function<ThrowCompletionOr<void>(Value)> = {}); FunctionObject* species_constructor(GlobalObject&, Object const&, FunctionObject& default_constructor); Realm* get_function_realm(GlobalObject&, FunctionObject const&); bool is_compatible_property_descriptor(bool extensible, PropertyDescriptor const&, Optional<PropertyDescriptor> const& current); diff --git a/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp b/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp index 6472ec7674..75b0a34ab2 100644 --- a/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp @@ -57,9 +57,7 @@ JS_DEFINE_NATIVE_FUNCTION(FunctionPrototype::apply) auto arg_array = vm.argument(1); if (arg_array.is_nullish()) return vm.call(function, this_arg); - auto arguments = create_list_from_array_like(global_object, arg_array); - if (vm.exception()) - return {}; + auto arguments = TRY_OR_DISCARD(create_list_from_array_like(global_object, arg_array)); return vm.call(function, this_arg, move(arguments)); } diff --git a/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp b/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp index 3637b07f50..39d99f6017 100644 --- a/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp @@ -817,16 +817,19 @@ MarkedValueList ProxyObject::internal_own_property_keys() const // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray, « String, Symbol »). HashTable<StringOrSymbol> unique_keys; - auto trap_result = create_list_from_array_like(global_object, trap_result_array, [&](auto value) { + auto throw_completion_or_trap_result = create_list_from_array_like(global_object, trap_result_array, [&](auto value) -> ThrowCompletionOr<void> { auto& vm = global_object.vm(); - if (!value.is_string() && !value.is_symbol()) { - vm.throw_exception<TypeError>(global_object, ErrorType::ProxyOwnPropertyKeysNotStringOrSymbol); - return; - } + if (!value.is_string() && !value.is_symbol()) + return vm.throw_completion<TypeError>(global_object, ErrorType::ProxyOwnPropertyKeysNotStringOrSymbol); auto property_key = value.to_property_key(global_object); VERIFY(!vm.exception()); unique_keys.set(property_key, AK::HashSetExistingEntryBehavior::Keep); + return {}; }); + // TODO: This becomes a lot nicer once this function returns a ThrowCompletionOr as well. + if (throw_completion_or_trap_result.is_throw_completion()) + return MarkedValueList { heap() }; + auto trap_result = throw_completion_or_trap_result.release_value(); // 9. If trapResult contains any duplicate entries, throw a TypeError exception. if (unique_keys.size() != trap_result.size()) { diff --git a/Userland/Libraries/LibJS/Runtime/ReflectObject.cpp b/Userland/Libraries/LibJS/Runtime/ReflectObject.cpp index b138bedb1c..b15131a6d4 100644 --- a/Userland/Libraries/LibJS/Runtime/ReflectObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ReflectObject.cpp @@ -61,9 +61,7 @@ JS_DEFINE_NATIVE_FUNCTION(ReflectObject::apply) } // 2. Let args be ? CreateListFromArrayLike(argumentsList). - auto args = create_list_from_array_like(global_object, arguments_list); - if (vm.exception()) - return {}; + auto args = TRY_OR_DISCARD(create_list_from_array_like(global_object, arguments_list)); // 3. Perform PrepareForTailCall(). // 4. Return ? Call(target, thisArgument, args). @@ -94,9 +92,7 @@ JS_DEFINE_NATIVE_FUNCTION(ReflectObject::construct) } // 4. Let args be ? CreateListFromArrayLike(argumentsList). - auto args = create_list_from_array_like(global_object, arguments_list); - if (vm.exception()) - return {}; + auto args = TRY_OR_DISCARD(create_list_from_array_like(global_object, arguments_list)); // 5. Return ? Construct(target, args, newTarget). return vm.construct(target.as_function(), new_target.as_function(), move(args)); |