diff options
author | davidot <david.tuin@gmail.com> | 2021-06-12 19:24:30 +0200 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2021-06-14 09:57:06 +0100 |
commit | d723c01af7e152b33cd3fddd083f71a39681f702 (patch) | |
tree | 1bdf0da7acd79e4568b2b3b60e55857dfbb8fac3 /Userland/Libraries | |
parent | 7c1e2adf8a1fe2667378f734f0cf22ec625ab55c (diff) | |
download | serenity-d723c01af7e152b33cd3fddd083f71a39681f702.zip |
LibJS: Make Array.prototype.unshift generic
Diffstat (limited to 'Userland/Libraries')
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp | 50 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype-generic-functions.js | 20 |
2 files changed, 65 insertions, 5 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp index 64187d3af6..0c5382b42f 100644 --- a/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp @@ -203,12 +203,52 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::push) // 23.1.3.31 Array.prototype.unshift ( ...items ), https://tc39.es/ecma262/#sec-array.prototype.unshift JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::unshift) { - auto* array = Array::typed_this(vm, global_object); - if (!array) + auto* this_object = vm.this_value(global_object).to_object(global_object); + if (!this_object) + return {}; + auto length = length_of_array_like(global_object, *this_object); + if (vm.exception()) + return {}; + auto arg_count = vm.argument_count(); + size_t new_length = length + arg_count; + if (arg_count > 0) { + if (new_length > MAX_ARRAY_LIKE_INDEX) { + vm.throw_exception<TypeError>(global_object, ErrorType::ArrayMaxSize); + return {}; + } + + for (size_t k = length; k > 0; --k) { + auto from = k - 1; + auto to = k + arg_count - 1; + + bool from_present = this_object->has_property(from); + if (vm.exception()) + return {}; + if (from_present) { + auto from_value = this_object->get(from).value_or(js_undefined()); + if (vm.exception()) + return {}; + this_object->put(to, from_value); + if (vm.exception()) + return {}; + } else { + this_object->delete_property(to); + if (vm.exception()) + return {}; + } + } + + for (size_t j = 0; j < arg_count; j++) { + this_object->put(j, vm.argument(j)); + if (vm.exception()) + return {}; + } + } + + this_object->put(vm.names.length, Value(new_length)); + if (vm.exception()) return {}; - for (size_t i = 0; i < vm.argument_count(); ++i) - array->indexed_properties().insert(i, vm.argument(i)); - return Value(static_cast<i32>(array->indexed_properties().array_like_size())); + return Value(new_length); } // 23.1.3.19 Array.prototype.pop ( ), https://tc39.es/ecma262/#sec-array.prototype.pop diff --git a/Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype-generic-functions.js b/Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype-generic-functions.js index b86cc0d4c5..c35a17719e 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype-generic-functions.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype-generic-functions.js @@ -110,6 +110,26 @@ describe("ability to work with generic non-array objects", () => { expect(o).toEqual({ length: 4, 0: "b", 2: "c" }); }); + test("unshift", () => { + { + const o = { length: 5, 0: "a", 1: "b", 3: "c" }; + const front = "z"; + Array.prototype.unshift.call(o, front); + expect(o[0]).toEqual(front); + expect(o[1]).toEqual("a"); + expect(o.length).toEqual(6); + } + { + const o = { length: 5, 0: "a", 1: "b", 3: "c" }; + const front = "z"; + Array.prototype.unshift.call(o, front, front); + expect(o[0]).toEqual(front); + expect(o[1]).toEqual(front); + expect(o[2]).toEqual("a"); + expect(o.length).toEqual(7); + } + }); + const o = { length: 5, 0: "foo", 1: "bar", 3: "baz" }; test("every", () => { |