Procházet zdrojové kódy

LibJS: Implement Array length setter

Linus Groh před 5 roky
rodič
revize
418092a71a

+ 24 - 6
Libraries/LibJS/Runtime/Array.cpp

@@ -49,19 +49,37 @@ Array::~Array()
 {
 }
 
-Value Array::length_getter(Interpreter& interpreter)
+Array* array_from(Interpreter& interpreter)
 {
     auto* this_object = interpreter.this_value().to_object(interpreter.heap());
     if (!this_object)
         return {};
-    if (!this_object->is_array())
-        return interpreter.throw_exception<TypeError>("Not an array");
-    return Value(static_cast<const Array*>(this_object)->length());
+    if (!this_object->is_array()) {
+        interpreter.throw_exception<TypeError>("Not an Array");
+        return nullptr;
+    }
+    return static_cast<Array*>(this_object);
+}
+
+Value Array::length_getter(Interpreter& interpreter)
+{
+    auto* array = array_from(interpreter);
+    if (!array)
+        return {};
+    return Value(array->length());
 }
 
-void Array::length_setter(Interpreter&, Value)
+void Array::length_setter(Interpreter& interpreter, Value value)
 {
-    ASSERT_NOT_REACHED();
+    auto* array = array_from(interpreter);
+    if (!array)
+        return;
+    auto length = value.to_number();
+    if (length.is_nan() || length.is_infinity() || length.as_double() < 0) {
+        interpreter.throw_exception<RangeError>("Invalid array length");
+        return;
+    }
+    array->elements().resize(length.as_double());
 }
 
 }

+ 2 - 1
Libraries/LibJS/Runtime/Array.h

@@ -30,6 +30,8 @@
 
 namespace JS {
 
+Array* array_from(Interpreter&);
+
 class Array final : public Object {
 public:
     static Array* create(GlobalObject&);
@@ -47,5 +49,4 @@ private:
     static void length_setter(Interpreter&, Value);
 };
 
-
 }

+ 0 - 12
Libraries/LibJS/Runtime/ArrayPrototype.cpp

@@ -63,18 +63,6 @@ ArrayPrototype::~ArrayPrototype()
 {
 }
 
-static Array* array_from(Interpreter& interpreter)
-{
-    auto* this_object = interpreter.this_value().to_object(interpreter.heap());
-    if (!this_object)
-        return {};
-    if (!this_object->is_array()) {
-        interpreter.throw_exception<TypeError>("Not an Array");
-        return nullptr;
-    }
-    return static_cast<Array*>(this_object);
-}
-
 static Function* callback_from_args(Interpreter& interpreter, const String& name)
 {
     if (interpreter.argument_count() < 1) {

+ 48 - 0
Libraries/LibJS/Tests/array-length-setter.js

@@ -0,0 +1,48 @@
+load("test-common.js");
+
+try {
+    var a = [1, 2, 3];
+
+    assert(a.length === 3);
+    assert(a[0] === 1);
+    assert(a[1] === 2);
+    assert(a[2] === 3);
+
+    a.length = 5;
+    assert(a.length === 5);
+    assert(a[0] === 1);
+    assert(a[1] === 2);
+    assert(a[2] === 3);
+    assert(a[3] === undefined);
+    assert(a[4] === undefined);
+
+    a.length = 1;
+    assert(a.length === 1);
+    assert(a[0] === 1);
+
+    a.length = 0;
+    assert(a.length === 0);
+
+    a.length = "42";
+    assert(a.length === 42);
+
+    a.length = [];
+    assert(a.length === 0);
+
+    a.length = true;
+    assert(a.length === 1);
+
+    [undefined, "foo", -1, Infinity, -Infinity, NaN].forEach(value => {
+        assertThrowsError(() => {
+            a.length = value;
+        }, {
+            error: RangeError,
+            message: "Invalid array length"
+        });
+        assert(a.length === 1);
+    });
+
+    console.log("PASS");
+} catch (e) {
+    console.log("FAIL: " + e);
+}