Explorar o código

LibJS: Implement the CreateListFromArrayLike() abstract operation

We already have two separate implementations of this, so let's do it
properly. The optional value type check is done by a callback function
that returns Result<void, ErrorType> - value type accepted or message
for TypeError, that is.
Linus Groh %!s(int64=4) %!d(string=hai) anos
pai
achega
ad7aa05cc6

+ 1 - 0
Userland/Libraries/LibJS/Forward.h

@@ -111,6 +111,7 @@ class Cell;
 class Console;
 class Console;
 class DeferGC;
 class DeferGC;
 class Error;
 class Error;
+class ErrorType;
 class Exception;
 class Exception;
 class Expression;
 class Expression;
 class Accessor;
 class Accessor;

+ 32 - 0
Userland/Libraries/LibJS/Runtime/Value.cpp

@@ -7,6 +7,7 @@
 
 
 #include <AK/AllOf.h>
 #include <AK/AllOf.h>
 #include <AK/FlyString.h>
 #include <AK/FlyString.h>
+#include <AK/Result.h>
 #include <AK/String.h>
 #include <AK/String.h>
 #include <AK/StringBuilder.h>
 #include <AK/StringBuilder.h>
 #include <AK/Utf8View.h>
 #include <AK/Utf8View.h>
@@ -1418,4 +1419,35 @@ Value require_object_coercible(GlobalObject& global_object, Value value)
     return value;
     return value;
 }
 }
 
 
+// 7.3.19 CreateListFromArrayLike, https://tc39.es/ecma262/#sec-createlistfromarraylike
+MarkedValueList create_list_from_array_like(GlobalObject& global_object, Value value, AK::Function<Result<void, ErrorType>(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 };
+    }
+    auto& array_like = value.as_object();
+    auto length = length_of_array_like(global_object, array_like);
+    if (vm.exception())
+        return MarkedValueList { heap };
+    auto list = MarkedValueList { heap };
+    for (size_t i = 0; i < length; ++i) {
+        auto index_name = String::number(i);
+        auto next = array_like.get(index_name).value_or(js_undefined());
+        if (vm.exception())
+            return MarkedValueList { heap };
+        if (check_value) {
+            auto result = check_value(next);
+            if (result.is_error()) {
+                vm.throw_exception<TypeError>(global_object, result.release_error());
+                return MarkedValueList { heap };
+            }
+        }
+        list.append(next);
+    }
+    return list;
+}
+
 }
 }

+ 3 - 0
Userland/Libraries/LibJS/Runtime/Value.h

@@ -11,6 +11,8 @@
 #include <AK/BitCast.h>
 #include <AK/BitCast.h>
 #include <AK/Format.h>
 #include <AK/Format.h>
 #include <AK/Forward.h>
 #include <AK/Forward.h>
+#include <AK/Function.h>
+#include <AK/Result.h>
 #include <AK/String.h>
 #include <AK/String.h>
 #include <AK/Types.h>
 #include <AK/Types.h>
 #include <LibJS/Forward.h>
 #include <LibJS/Forward.h>
@@ -372,6 +374,7 @@ Function* get_method(GlobalObject& global_object, Value, const PropertyName&);
 size_t length_of_array_like(GlobalObject&, const Object&);
 size_t length_of_array_like(GlobalObject&, const Object&);
 Object* species_constructor(GlobalObject&, const Object&, Object& default_constructor);
 Object* species_constructor(GlobalObject&, const Object&, Object& default_constructor);
 Value require_object_coercible(GlobalObject&, Value);
 Value require_object_coercible(GlobalObject&, Value);
+MarkedValueList create_list_from_array_like(GlobalObject&, Value, AK::Function<Result<void, ErrorType>(Value)> = {});
 
 
 }
 }