diff --git a/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp index dd2ad8dcdc..9a590f13cb 100644 --- a/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp @@ -1445,158 +1445,87 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::sort) // 23.1.3.31 Array.prototype.splice ( start, deleteCount, ...items ), https://tc39.es/ecma262/#sec-array.prototype.splice JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::splice) { - // 1. Let O be ? ToObject(this value). auto this_object = TRY(vm.this_value().to_object(vm)); - // 2. Let len be ? LengthOfArrayLike(O). auto initial_length = TRY(length_of_array_like(vm, this_object)); - // 3. Let relativeStart be ? ToIntegerOrInfinity(start). auto relative_start = TRY(vm.argument(0).to_integer_or_infinity(vm)); + if (Value(relative_start).is_negative_infinity()) + relative_start = 0; + u64 actual_start; - // 4. If relativeStart = -∞, let actualStart be 0. - if (Value(relative_start).is_negative_infinity()) - actual_start = 0; - // 5. Else if relativeStart < 0, let actualStart be max(len + relativeStart, 0). - else if (relative_start < 0) + if (relative_start < 0) actual_start = max((ssize_t)initial_length + relative_start, (ssize_t)0); - // 6. Else, let actualStart be min(relativeStart, len). else actual_start = min(relative_start, initial_length); - // 7. Let itemCount be the number of elements in items. - u64 item_count = vm.argument_count() >= 2 ? vm.argument_count() - 2 : 0; + u64 insert_count = 0; + double actual_delete_count = 0; - u64 actual_delete_count; - - // 8. If start is not present, then - if (vm.argument_count() == 0) { - // a. Let actualDeleteCount be 0. - actual_delete_count = 0; - } - // 9. Else if deleteCount is not present, then - else if (vm.argument_count() == 1) { - // a. Let actualDeleteCount be len - actualStart. + if (vm.argument_count() == 1) { actual_delete_count = initial_length - actual_start; - } - // 10. Else, - else { - // a. Let dc be ? ToIntegerOrInfinity(deleteCount). + } else if (vm.argument_count() >= 2) { + insert_count = vm.argument_count() - 2; auto delete_count = TRY(vm.argument(1).to_integer_or_infinity(vm)); - - // b. Let actualDeleteCount be the result of clamping dc between 0 and len - actualStart. - actual_delete_count = clamp(delete_count, 0, initial_length - actual_start); + auto temp = max(delete_count, 0); + actual_delete_count = min(temp, initial_length - actual_start); } - // 11. If len + itemCount - actualDeleteCount > 2^53 - 1, throw a TypeError exception. - if (initial_length + item_count - actual_delete_count > MAX_ARRAY_LIKE_INDEX) + double new_length = initial_length + insert_count - actual_delete_count; + + if (new_length > MAX_ARRAY_LIKE_INDEX) return vm.throw_completion(ErrorType::ArrayMaxSize); - // 12. Let A be ? ArraySpeciesCreate(O, actualDeleteCount). auto* removed_elements = TRY(array_species_create(vm, this_object, actual_delete_count)); - // 13. Let k be 0. - // 14. Repeat, while k < actualDeleteCount, - for (u64 k = 0; k < actual_delete_count; ++k) { - // a. Let from be ! ToString(𝔽(actualStart + k)). - auto from = PropertyKey { actual_start + k }; + for (u64 i = 0; i < actual_delete_count; ++i) { + auto from = actual_start + i; - // b. If ? HasProperty(O, from) is true, then if (TRY(this_object->has_property(from))) { - // i. Let fromValue be ? Get(O, from). auto from_value = TRY(this_object->get(from)); - // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(𝔽(k)), fromValue). - TRY(removed_elements->create_data_property_or_throw(k, from_value)); + TRY(removed_elements->create_data_property_or_throw(i, from_value)); } - - // c. Set k to k + 1. } - // 15. Perform ? Set(A, "length", 𝔽(actualDeleteCount), true). TRY(removed_elements->set(vm.names.length, Value(actual_delete_count), Object::ShouldThrowExceptions::Yes)); - // 16. If itemCount < actualDeleteCount, then - if (item_count < actual_delete_count) { - // a. Set k to actualStart. - // b. Repeat, while k < (len - actualDeleteCount), - for (u64 k = actual_start; k < initial_length - actual_delete_count; ++k) { - // i. Let from be ! ToString(𝔽(k + actualDeleteCount)). - auto from = PropertyKey { k + actual_delete_count }; + if (insert_count < actual_delete_count) { + for (u64 i = actual_start; i < initial_length - actual_delete_count; ++i) { + auto to = i + insert_count; + u64 from = i + actual_delete_count; - // ii. Let to be ! ToString(𝔽(k + itemCount)). - auto to = PropertyKey { k + item_count }; - - // iii. If ? HasProperty(O, from) is true, then if (TRY(this_object->has_property(from))) { - // 1. Let fromValue be ? Get(O, from). auto from_value = TRY(this_object->get(from)); - - // 2. Perform ? Set(O, to, fromValue, true). TRY(this_object->set(to, from_value, Object::ShouldThrowExceptions::Yes)); - } - // iv. Else, - else { - // 1. Perform ? DeletePropertyOrThrow(O, to). + } else { TRY(this_object->delete_property_or_throw(to)); } - - // v. Set k to k + 1. } - // c. Set k to len. - // d. Repeat, while k > (len - actualDeleteCount + itemCount), - for (u64 k = initial_length; k > initial_length - actual_delete_count + item_count; --k) { - // i. Perform ? DeletePropertyOrThrow(O, ! ToString(𝔽(k - 1))). - TRY(this_object->delete_property_or_throw(k - 1)); + for (u64 i = initial_length; i > new_length; --i) + TRY(this_object->delete_property_or_throw(i - 1)); + } else if (insert_count > actual_delete_count) { + for (u64 i = initial_length - actual_delete_count; i > actual_start; --i) { + u64 from_index = i + actual_delete_count - 1; + auto to = i + insert_count - 1; - // ii. Set k to k - 1. - } - } - // 17. Else if itemCount > actualDeleteCount, then - else if (item_count > actual_delete_count) { - // a. Set k to (len - actualDeleteCount). - // b. Repeat, while k > actualStart, - for (u64 k = initial_length - actual_delete_count; k > actual_start; --k) { - // i. Let from be ! ToString(𝔽(k + actualDeleteCount - 1)). - auto from = PropertyKey { k + actual_delete_count - 1 }; - - // ii. Let to be ! ToString(𝔽(k + itemCount - 1)). - auto to = PropertyKey { k + item_count - 1 }; - - // iii. If ? HasProperty(O, from) is true, then - if (TRY(this_object->has_property(from))) { - // 1. Let fromValue be ? Get(O, from). - auto from_value = TRY(this_object->get(from)); - - // 2. Perform ? Set(O, to, fromValue, true). + if (TRY(this_object->has_property(from_index))) { + auto from_value = TRY(this_object->get(from_index)); TRY(this_object->set(to, from_value, Object::ShouldThrowExceptions::Yes)); - } - // iv. Else, - else { - // 1. Perform ? DeletePropertyOrThrow(O, to). + } else { TRY(this_object->delete_property_or_throw(to)); } - - // v. Set k to k - 1. } } - // 18. Set k to actualStart. - // 19. For each element E of items, do - for (u64 k = actual_start; k < actual_start + item_count; ++k) { - // a. Perform ? Set(O, ! ToString(𝔽(k)), E, true). - TRY(this_object->set(k, vm.argument(k + 2), Object::ShouldThrowExceptions::Yes)); + for (u64 i = 0; i < insert_count; ++i) + TRY(this_object->set(actual_start + i, vm.argument(i + 2), Object::ShouldThrowExceptions::Yes)); - // b. Set k to k + 1. - } + TRY(this_object->set(vm.names.length, Value(new_length), Object::ShouldThrowExceptions::Yes)); - // 20. Perform ? Set(O, "length", 𝔽(len - actualDeleteCount + itemCount), true). - TRY(this_object->set(vm.names.length, Value(initial_length - actual_delete_count + item_count), Object::ShouldThrowExceptions::Yes)); - - // 21. Return A. return removed_elements; }