Przeglądaj źródła

LibJS: Use ThrowCompletionOr in create_list_from_array_like()

Also add spec step comments to it while we're here.
Linus Groh 3 lat temu
rodzic
commit
c4c40f4cf3

+ 30 - 14
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;
 }
 

+ 1 - 1
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);

+ 1 - 3
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));
 }
 

+ 8 - 5
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()) {

+ 2 - 6
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));