From f44a83e38c33b04a89700615c15084c7ad8868f6 Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Sun, 27 Jun 2021 19:47:41 +0100
Subject: [PATCH 01/16] feat(boa): adds splice method

- adds array.prototype.splice
- todo: fix stalls at certain testcases

Closes #36
---
 boa/src/builtins/array/mod.rs | 128 ++++++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index daaa5d10865..e2f55af8b11 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -108,6 +108,7 @@ impl BuiltIn for Array {
         .method(Self::flat_map, "flatMap", 1)
         .method(Self::slice, "slice", 2)
         .method(Self::some, "some", 2)
+        .method(Self::splice, "splice", 3)
         .method(Self::reduce, "reduce", 2)
         .method(Self::reduce_right, "reduceRight", 2)
         .method(Self::keys, "keys", 0)
@@ -1512,6 +1513,133 @@ impl Array {
         Ok(new_array)
     }
 
+    pub(crate) fn splice(this: &Value, args: &[Value], context: &mut Context) -> Result<Value> {
+        let o = this.to_object(context)?;
+        let len = this.get_field("length", context)?.to_length(context)?;
+        let actual_start = Self::get_relative_start(context, args.get(0), len)?;
+        let insert_count = if args.get(0).is_none() || args.get(1).is_none() {
+            0
+        } else {
+            args.len()
+        };
+        let actual_delete_count = if args.get(0).is_none() {
+            0
+        } else if args.get(1).is_none() {
+            len - actual_start
+        } else {
+            let dc = args.get(1).ok_or(0)?.to_integer_or_infinity(context)?;
+            let max = len - actual_start;
+            match dc {
+                IntegerOrInfinity::Integer(i) => {
+                    if i < 0 {
+                        0
+                    } else if i as usize > max {
+                        max
+                    } else {
+                        i as usize
+                    }
+                }
+                IntegerOrInfinity::PositiveInfinity => max,
+                IntegerOrInfinity::NegativeInfinity => 0,
+            }
+        };
+
+        if len + insert_count - actual_delete_count > Number::MAX_SAFE_INTEGER as usize {
+            return context.throw_type_error("Target splice exceeded max safe integer value");
+        }
+
+        let arr = Self::array_species_create(&o, actual_delete_count as u32, context)?;
+
+        for k in 0..actual_delete_count {
+            let from_present = this.has_field(actual_start + k);
+            if from_present {
+                let from_value = this.get_field(actual_start + k, context)?;
+                let fv = DataDescriptor::new(
+                    from_value,
+                    Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+                );
+                arr.set_property(actual_start + k, fv);
+            }
+        }
+
+        let acd = DataDescriptor::new(
+            Value::from(len),
+            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+        );
+
+        arr.set_property("length", acd);
+
+        let items = match args.len() {
+            0 | 1 | 2 => args.split_at(0).0, // empty arr
+            _ => args.split_at(2).1
+        };
+
+        let item_count = items.len();
+
+        match item_count {
+          ic if ic < actual_delete_count => {
+              for k in actual_start..len-actual_delete_count {
+                  let from = k + actual_delete_count;
+                  let to = k + item_count;
+                  let from_present = this.has_field(from);
+                  if from_present {
+                      let from_value = this.get_field(from, context)?;
+                      let fv = DataDescriptor::new(
+                          from_value,
+                          Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+                      );
+                      this.set_property(to, fv);
+                  } else {
+                      debug_assert!(!from_present);
+                      this.remove_property(to);
+                  }
+              }
+              for k in ((len-actual_delete_count+item_count)+1..=len).rev() {
+                  this.remove_property(k-1);
+              }
+          },
+          ic if ic > actual_delete_count => {
+              for k in (actual_start+1..=len-actual_delete_count).rev() {
+                  let from = k + actual_delete_count - 1;
+                  let to = k + item_count - 1;
+                  let from_present = this.has_field(from);
+                  if from_present {
+                      let from_value = this.get_field(from, context)?;
+                      let fv = DataDescriptor::new(
+                          from_value,
+                          Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+                      );
+                      this.set_property(to, fv);
+                  } else {
+                      debug_assert!(!from_present);
+                      this.remove_property(to);
+                  }
+              }
+          },
+          _ => {}
+        };
+
+        let mut k = actual_start;
+
+        for item in items {
+            let prop = DataDescriptor::new(
+                item,
+                Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+            );
+            this.set_property(k, prop);
+            k += 1;
+        }
+
+        let length = DataDescriptor::new(
+            Value::from(len-actual_delete_count+item_count),
+            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+        );
+
+        this.set_property("length", length);
+
+        Ok(arr)
+    }
+
     /// `Array.prototype.filter( callback, [ thisArg ] )`
     ///
     /// For each element in the array the callback function is called, and a new

From 02b431ebee8f51344e89e5a72f014698ba05e1f4 Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Sun, 27 Jun 2021 19:55:38 +0100
Subject: [PATCH 02/16] fix rust_fmt

---
 boa/src/builtins/array/mod.rs | 84 +++++++++++++++++------------------
 1 file changed, 42 insertions(+), 42 deletions(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index e2f55af8b11..747569716d5 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1571,52 +1571,52 @@ impl Array {
 
         let items = match args.len() {
             0 | 1 | 2 => args.split_at(0).0, // empty arr
-            _ => args.split_at(2).1
+            _ => args.split_at(2).1,
         };
 
         let item_count = items.len();
 
         match item_count {
-          ic if ic < actual_delete_count => {
-              for k in actual_start..len-actual_delete_count {
-                  let from = k + actual_delete_count;
-                  let to = k + item_count;
-                  let from_present = this.has_field(from);
-                  if from_present {
-                      let from_value = this.get_field(from, context)?;
-                      let fv = DataDescriptor::new(
-                          from_value,
-                          Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-                      );
-                      this.set_property(to, fv);
-                  } else {
-                      debug_assert!(!from_present);
-                      this.remove_property(to);
-                  }
-              }
-              for k in ((len-actual_delete_count+item_count)+1..=len).rev() {
-                  this.remove_property(k-1);
-              }
-          },
-          ic if ic > actual_delete_count => {
-              for k in (actual_start+1..=len-actual_delete_count).rev() {
-                  let from = k + actual_delete_count - 1;
-                  let to = k + item_count - 1;
-                  let from_present = this.has_field(from);
-                  if from_present {
-                      let from_value = this.get_field(from, context)?;
-                      let fv = DataDescriptor::new(
-                          from_value,
-                          Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-                      );
-                      this.set_property(to, fv);
-                  } else {
-                      debug_assert!(!from_present);
-                      this.remove_property(to);
-                  }
-              }
-          },
-          _ => {}
+            ic if ic < actual_delete_count => {
+                for k in actual_start..len - actual_delete_count {
+                    let from = k + actual_delete_count;
+                    let to = k + item_count;
+                    let from_present = this.has_field(from);
+                    if from_present {
+                        let from_value = this.get_field(from, context)?;
+                        let fv = DataDescriptor::new(
+                            from_value,
+                            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+                        );
+                        this.set_property(to, fv);
+                    } else {
+                        debug_assert!(!from_present);
+                        this.remove_property(to);
+                    }
+                }
+                for k in ((len - actual_delete_count + item_count) + 1..=len).rev() {
+                    this.remove_property(k - 1);
+                }
+            }
+            ic if ic > actual_delete_count => {
+                for k in (actual_start + 1..=len - actual_delete_count).rev() {
+                    let from = k + actual_delete_count - 1;
+                    let to = k + item_count - 1;
+                    let from_present = this.has_field(from);
+                    if from_present {
+                        let from_value = this.get_field(from, context)?;
+                        let fv = DataDescriptor::new(
+                            from_value,
+                            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+                        );
+                        this.set_property(to, fv);
+                    } else {
+                        debug_assert!(!from_present);
+                        this.remove_property(to);
+                    }
+                }
+            }
+            _ => {}
         };
 
         let mut k = actual_start;
@@ -1631,7 +1631,7 @@ impl Array {
         }
 
         let length = DataDescriptor::new(
-            Value::from(len-actual_delete_count+item_count),
+            Value::from(len - actual_delete_count + item_count),
             Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
         );
 

From 272a756a6cdf351f7951477ce5e46f205e005e59 Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Thu, 22 Jul 2021 00:06:51 +0100
Subject: [PATCH 03/16] add docs

---
 boa/src/builtins/array/mod.rs | 106 ++++++++++++++++++++++++++++------
 boa/src/value/mod.rs          |  13 +++++
 2 files changed, 101 insertions(+), 18 deletions(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index 747569716d5..4021aa71d29 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1512,22 +1512,41 @@ impl Array {
         new_array.set_field("length", Value::from(new_array_len), true, context)?;
         Ok(new_array)
     }
+    /// `Array.prototype.splice ( start, [deleteCount[, ...items]] )`
+    ///
+    /// Splices an array by following
+    /// The deleteCount elements of the array starting at integer index start are replaced by the elements of items.
+    /// An Array object containing the deleted elements (if any) is returned.
 
     pub(crate) fn splice(this: &Value, args: &[Value], context: &mut Context) -> Result<Value> {
+        // 1. Let O be ? ToObject(this value).
         let o = this.to_object(context)?;
+        // 2. Let len be ? LengthOfArrayLike(O).
         let len = this.get_field("length", context)?.to_length(context)?;
+        // 3. Let relativeStart be ? ToIntegerOrInfinity(start).
+        // 4. If relativeStart is -∞, let actualStart be 0.
+        // 5. Else if relativeStart < 0, let actualStart be max(len + relativeStart, 0).
+        // 6. Else, let actualStart be min(relativeStart, len).
         let actual_start = Self::get_relative_start(context, args.get(0), len)?;
+        // 7. If start is not present, then
         let insert_count = if args.get(0).is_none() || args.get(1).is_none() {
+            // 7a. Let insertCount be 0.
+            // 8a. Let insertCount be 0.
             0
         } else {
+            // 9a. Let insertCount be the number of elements in items.
             args.len()
         };
         let actual_delete_count = if args.get(0).is_none() {
+            // 7b. Let actualDeleteCount be 0.
             0
         } else if args.get(1).is_none() {
+            // 8b. Let actualDeleteCount be len - actualStart.
             len - actual_start
         } else {
+            // 9b. Let dc be ? ToIntegerOrInfinity(deleteCount).
             let dc = args.get(1).ok_or(0)?.to_integer_or_infinity(context)?;
+            // c. Let actualDeleteCount be the result of clamping dc between 0 and len - actualStart.
             let max = len - actual_start;
             match dc {
                 IntegerOrInfinity::Integer(i) => {
@@ -1543,93 +1562,143 @@ impl Array {
                 IntegerOrInfinity::NegativeInfinity => 0,
             }
         };
-
+        // 10. If len + insertCount - actualDeleteCount > 253 - 1, throw a TypeError exception.
         if len + insert_count - actual_delete_count > Number::MAX_SAFE_INTEGER as usize {
             return context.throw_type_error("Target splice exceeded max safe integer value");
         }
 
+        //temp until arrayspecies merges
+        if actual_delete_count >= u32::MAX as usize {
+            return context.throw_type_error("Target splice exceeded max safe integer value");
+        }
+        // -------------------------------
+
+        // 11. Let A be ? ArraySpeciesCreate(O, actualDeleteCount).
         let arr = Self::array_species_create(&o, actual_delete_count as u32, context)?;
 
+        // 12. Let k be 0.
+        // 13. Repeat, while k < actualDeleteCount,
         for k in 0..actual_delete_count {
+            // a. Let from be ! ToString(𝔽(actualStart + k)).
+            // b. Let fromPresent be ? HasProperty(O, from).
             let from_present = this.has_field(actual_start + k);
+            // c. If fromPresent is true, then
             if from_present {
+                // i. Let fromValue be ? Get(O, from).
                 let from_value = this.get_field(actual_start + k, context)?;
+                // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(𝔽(k)), fromValue).
                 let fv = DataDescriptor::new(
                     from_value,
                     Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
                 );
                 arr.set_property(actual_start + k, fv);
             }
+            // d. Set k to k + 1.
         }
 
+        // 14. Perform ? Set(A, "length", 𝔽(actualDeleteCount), true).
         let acd = DataDescriptor::new(
-            Value::from(len),
+            Value::from(actual_delete_count),
             Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
         );
 
         arr.set_property("length", acd);
 
-        let items = match args.len() {
-            0 | 1 | 2 => args.split_at(0).0, // empty arr
-            _ => args.split_at(2).1,
-        };
-
-        let item_count = items.len();
+        // 15. Let itemCount be the number of elements in items.
+        let item_count = args.len().saturating_sub(2);
 
         match item_count {
+            // 16. If itemCount < actualDeleteCount, then
             ic if ic < actual_delete_count => {
+                //     a. Set k to actualStart.
+                //     b. Repeat, while k < (len - actualDeleteCount),
                 for k in actual_start..len - actual_delete_count {
+                    // i. Let from be ! ToString(𝔽(k + actualDeleteCount)).
                     let from = k + actual_delete_count;
+                    // ii. Let to be ! ToString(𝔽(k + itemCount)).
                     let to = k + item_count;
+                    // iii. Let fromPresent be ? HasProperty(O, from).
                     let from_present = this.has_field(from);
+                    // iv. If fromPresent is true, then
                     if from_present {
+                        // 1. Let fromValue be ? Get(O, from).
                         let from_value = this.get_field(from, context)?;
+                        // 2. Perform ? Set(O, to, fromValue, true).
                         let fv = DataDescriptor::new(
                             from_value,
                             Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
                         );
                         this.set_property(to, fv);
+                    // v. Else,
                     } else {
+                        // 1. Assert: fromPresent is false.
                         debug_assert!(!from_present);
-                        this.remove_property(to);
+                        // 2. Perform ? DeletePropertyOrThrow(O, to).
+                        this.delete_property_or_throw(to, context)?;
                     }
+                    // vi. Set k to k + 1.
                 }
+                // c. Set k to len.
+                // d. Repeat, while k > (len - actualDeleteCount + itemCount),
                 for k in ((len - actual_delete_count + item_count) + 1..=len).rev() {
-                    this.remove_property(k - 1);
+                    // i. Perform ? DeletePropertyOrThrow(O, ! ToString(𝔽(k - 1))).
+                    this.delete_property_or_throw(k - 1, context)?;
+                    // ii. Set k to k - 1.
                 }
             }
+            // 17. Else if itemCount > actualDeleteCount, then
             ic if ic > actual_delete_count => {
+                // a. Set k to (len - actualDeleteCount).
+                // b. Repeat, while k > actualStart,
                 for k in (actual_start + 1..=len - actual_delete_count).rev() {
+                    // i. Let from be ! ToString(𝔽(k + actualDeleteCount - 1)).
                     let from = k + actual_delete_count - 1;
+                    // ii. Let to be ! ToString(𝔽(k + itemCount - 1)).
                     let to = k + item_count - 1;
+                    // iii. Let fromPresent be ? HasProperty(O, from).
                     let from_present = this.has_field(from);
+                    // iv. If fromPresent is true, then
                     if from_present {
+                        // 1. Let fromValue be ? Get(O, from).
                         let from_value = this.get_field(from, context)?;
+                        // 2. Perform ? Set(O, to, fromValue, true).
                         let fv = DataDescriptor::new(
                             from_value,
                             Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
                         );
                         this.set_property(to, fv);
+                    // v. Else,
                     } else {
+                        // 1. Assert: fromPresent is false.
                         debug_assert!(!from_present);
-                        this.remove_property(to);
+                        // 2. Perform ? DeletePropertyOrThrow(O, to).
+                        this.delete_property_or_throw(to, context)?;
                     }
+                    // vi. Set k to k - 1.
                 }
             }
             _ => {}
         };
 
+        // 18. Set k to actualStart.
         let mut k = actual_start;
 
-        for item in items {
-            let prop = DataDescriptor::new(
-                item,
-                Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-            );
-            this.set_property(k, prop);
-            k += 1;
+        // 19. For each element E of items, do
+        if item_count > 0 {
+            let items = args.split_at(2).1;
+            for item in items {
+                // a. Perform ? Set(O, ! ToString(𝔽(k)), E, true).
+                let prop = DataDescriptor::new(
+                    item,
+                    Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+                );
+                this.set_property(k, prop);
+                // b. Set k to k + 1.
+                k += 1;
+            }
         }
 
+        // 20. Perform ? Set(O, "length", 𝔽(len - actualDeleteCount + itemCount), true).
         let length = DataDescriptor::new(
             Value::from(len - actual_delete_count + item_count),
             Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
@@ -1637,6 +1706,7 @@ impl Array {
 
         this.set_property("length", length);
 
+        // 21. Return A.
         Ok(arr)
     }
 
diff --git a/boa/src/value/mod.rs b/boa/src/value/mod.rs
index 9c9a26a6dea..a6fa89c65f4 100644
--- a/boa/src/value/mod.rs
+++ b/boa/src/value/mod.rs
@@ -429,6 +429,19 @@ impl Value {
         self.as_object().map(|x| x.remove(&key.into())).is_some()
     }
 
+    pub fn delete_property_or_throw<Key>(&self, key: Key, context: &mut Context) -> Result<Value>
+    where
+        Key: Into<PropertyKey>,
+    {
+        debug_assert!(self.is_object());
+        // debug_assert!(self.get_property(key).is_some());
+        if self.remove_property(key) {
+            Ok(Value::from(true))
+        } else {
+            context.throw_type_error("Unable to delete property")
+        }
+    }
+
     /// Resolve the property in the object.
     ///
     /// A copy of the Property is returned.

From e8e43176e68a6ba3dd0fe64966b99725069fa861 Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Sun, 27 Jun 2021 19:47:41 +0100
Subject: [PATCH 04/16] feat(boa): adds splice method

- adds array.prototype.splice
- todo: fix stalls at certain testcases

Closes #36
---
 boa/src/builtins/array/mod.rs | 127 ++++++++++++++++++++++++++++++++++
 1 file changed, 127 insertions(+)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index 4021aa71d29..24391926784 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1710,6 +1710,133 @@ impl Array {
         Ok(arr)
     }
 
+    pub(crate) fn splice(this: &Value, args: &[Value], context: &mut Context) -> Result<Value> {
+        let o = this.to_object(context)?;
+        let len = this.get_field("length", context)?.to_length(context)?;
+        let actual_start = Self::get_relative_start(context, args.get(0), len)?;
+        let insert_count = if args.get(0).is_none() || args.get(1).is_none() {
+            0
+        } else {
+            args.len()
+        };
+        let actual_delete_count = if args.get(0).is_none() {
+            0
+        } else if args.get(1).is_none() {
+            len - actual_start
+        } else {
+            let dc = args.get(1).ok_or(0)?.to_integer_or_infinity(context)?;
+            let max = len - actual_start;
+            match dc {
+                IntegerOrInfinity::Integer(i) => {
+                    if i < 0 {
+                        0
+                    } else if i as usize > max {
+                        max
+                    } else {
+                        i as usize
+                    }
+                }
+                IntegerOrInfinity::PositiveInfinity => max,
+                IntegerOrInfinity::NegativeInfinity => 0,
+            }
+        };
+
+        if len + insert_count - actual_delete_count > Number::MAX_SAFE_INTEGER as usize {
+            return context.throw_type_error("Target splice exceeded max safe integer value");
+        }
+
+        let arr = Self::array_species_create(&o, actual_delete_count as u32, context)?;
+
+        for k in 0..actual_delete_count {
+            let from_present = this.has_field(actual_start + k);
+            if from_present {
+                let from_value = this.get_field(actual_start + k, context)?;
+                let fv = DataDescriptor::new(
+                    from_value,
+                    Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+                );
+                arr.set_property(actual_start + k, fv);
+            }
+        }
+
+        let acd = DataDescriptor::new(
+            Value::from(len),
+            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+        );
+
+        arr.set_property("length", acd);
+
+        let items = match args.len() {
+            0 | 1 | 2 => args.split_at(0).0, // empty arr
+            _ => args.split_at(2).1
+        };
+
+        let item_count = items.len();
+
+        match item_count {
+          ic if ic < actual_delete_count => {
+              for k in actual_start..len-actual_delete_count {
+                  let from = k + actual_delete_count;
+                  let to = k + item_count;
+                  let from_present = this.has_field(from);
+                  if from_present {
+                      let from_value = this.get_field(from, context)?;
+                      let fv = DataDescriptor::new(
+                          from_value,
+                          Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+                      );
+                      this.set_property(to, fv);
+                  } else {
+                      debug_assert!(!from_present);
+                      this.remove_property(to);
+                  }
+              }
+              for k in ((len-actual_delete_count+item_count)+1..=len).rev() {
+                  this.remove_property(k-1);
+              }
+          },
+          ic if ic > actual_delete_count => {
+              for k in (actual_start+1..=len-actual_delete_count).rev() {
+                  let from = k + actual_delete_count - 1;
+                  let to = k + item_count - 1;
+                  let from_present = this.has_field(from);
+                  if from_present {
+                      let from_value = this.get_field(from, context)?;
+                      let fv = DataDescriptor::new(
+                          from_value,
+                          Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+                      );
+                      this.set_property(to, fv);
+                  } else {
+                      debug_assert!(!from_present);
+                      this.remove_property(to);
+                  }
+              }
+          },
+          _ => {}
+        };
+
+        let mut k = actual_start;
+
+        for item in items {
+            let prop = DataDescriptor::new(
+                item,
+                Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+            );
+            this.set_property(k, prop);
+            k += 1;
+        }
+
+        let length = DataDescriptor::new(
+            Value::from(len-actual_delete_count+item_count),
+            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+        );
+
+        this.set_property("length", length);
+
+        Ok(arr)
+    }
+
     /// `Array.prototype.filter( callback, [ thisArg ] )`
     ///
     /// For each element in the array the callback function is called, and a new

From 1b1173c4ae3ff1b4e25926ed2718153990d73eab Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Sun, 27 Jun 2021 19:55:38 +0100
Subject: [PATCH 05/16] fix rust_fmt

---
 boa/src/builtins/array/mod.rs | 84 +++++++++++++++++------------------
 1 file changed, 42 insertions(+), 42 deletions(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index 24391926784..2836f915764 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1768,52 +1768,52 @@ impl Array {
 
         let items = match args.len() {
             0 | 1 | 2 => args.split_at(0).0, // empty arr
-            _ => args.split_at(2).1
+            _ => args.split_at(2).1,
         };
 
         let item_count = items.len();
 
         match item_count {
-          ic if ic < actual_delete_count => {
-              for k in actual_start..len-actual_delete_count {
-                  let from = k + actual_delete_count;
-                  let to = k + item_count;
-                  let from_present = this.has_field(from);
-                  if from_present {
-                      let from_value = this.get_field(from, context)?;
-                      let fv = DataDescriptor::new(
-                          from_value,
-                          Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-                      );
-                      this.set_property(to, fv);
-                  } else {
-                      debug_assert!(!from_present);
-                      this.remove_property(to);
-                  }
-              }
-              for k in ((len-actual_delete_count+item_count)+1..=len).rev() {
-                  this.remove_property(k-1);
-              }
-          },
-          ic if ic > actual_delete_count => {
-              for k in (actual_start+1..=len-actual_delete_count).rev() {
-                  let from = k + actual_delete_count - 1;
-                  let to = k + item_count - 1;
-                  let from_present = this.has_field(from);
-                  if from_present {
-                      let from_value = this.get_field(from, context)?;
-                      let fv = DataDescriptor::new(
-                          from_value,
-                          Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-                      );
-                      this.set_property(to, fv);
-                  } else {
-                      debug_assert!(!from_present);
-                      this.remove_property(to);
-                  }
-              }
-          },
-          _ => {}
+            ic if ic < actual_delete_count => {
+                for k in actual_start..len - actual_delete_count {
+                    let from = k + actual_delete_count;
+                    let to = k + item_count;
+                    let from_present = this.has_field(from);
+                    if from_present {
+                        let from_value = this.get_field(from, context)?;
+                        let fv = DataDescriptor::new(
+                            from_value,
+                            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+                        );
+                        this.set_property(to, fv);
+                    } else {
+                        debug_assert!(!from_present);
+                        this.remove_property(to);
+                    }
+                }
+                for k in ((len - actual_delete_count + item_count) + 1..=len).rev() {
+                    this.remove_property(k - 1);
+                }
+            }
+            ic if ic > actual_delete_count => {
+                for k in (actual_start + 1..=len - actual_delete_count).rev() {
+                    let from = k + actual_delete_count - 1;
+                    let to = k + item_count - 1;
+                    let from_present = this.has_field(from);
+                    if from_present {
+                        let from_value = this.get_field(from, context)?;
+                        let fv = DataDescriptor::new(
+                            from_value,
+                            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+                        );
+                        this.set_property(to, fv);
+                    } else {
+                        debug_assert!(!from_present);
+                        this.remove_property(to);
+                    }
+                }
+            }
+            _ => {}
         };
 
         let mut k = actual_start;
@@ -1828,7 +1828,7 @@ impl Array {
         }
 
         let length = DataDescriptor::new(
-            Value::from(len-actual_delete_count+item_count),
+            Value::from(len - actual_delete_count + item_count),
             Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
         );
 

From 316157eaeb02cd9a15068f6ae6812b59a51a433e Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Thu, 22 Jul 2021 00:06:51 +0100
Subject: [PATCH 06/16] add docs

---
 boa/src/builtins/array/mod.rs | 85 ++++++++++++++++++++++++++++-------
 boa/src/value/mod.rs          | 13 ++++++
 2 files changed, 81 insertions(+), 17 deletions(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index 2836f915764..69e7451a7e4 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1745,88 +1745,138 @@ impl Array {
             return context.throw_type_error("Target splice exceeded max safe integer value");
         }
 
+        //temp until arrayspecies merges
+        if actual_delete_count >= u32::MAX as usize {
+            return context.throw_type_error("Target splice exceeded max safe integer value");
+        }
+        // -------------------------------
+
+        // 11. Let A be ? ArraySpeciesCreate(O, actualDeleteCount).
         let arr = Self::array_species_create(&o, actual_delete_count as u32, context)?;
 
+        // 12. Let k be 0.
+        // 13. Repeat, while k < actualDeleteCount,
         for k in 0..actual_delete_count {
+            // a. Let from be ! ToString(𝔽(actualStart + k)).
+            // b. Let fromPresent be ? HasProperty(O, from).
             let from_present = this.has_field(actual_start + k);
+            // c. If fromPresent is true, then
             if from_present {
+                // i. Let fromValue be ? Get(O, from).
                 let from_value = this.get_field(actual_start + k, context)?;
+                // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(𝔽(k)), fromValue).
                 let fv = DataDescriptor::new(
                     from_value,
                     Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
                 );
                 arr.set_property(actual_start + k, fv);
             }
+            // d. Set k to k + 1.
         }
 
+        // 14. Perform ? Set(A, "length", 𝔽(actualDeleteCount), true).
         let acd = DataDescriptor::new(
-            Value::from(len),
+            Value::from(actual_delete_count),
             Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
         );
 
         arr.set_property("length", acd);
 
-        let items = match args.len() {
-            0 | 1 | 2 => args.split_at(0).0, // empty arr
-            _ => args.split_at(2).1,
-        };
-
-        let item_count = items.len();
+        // 15. Let itemCount be the number of elements in items.
+        let item_count = args.len().saturating_sub(2);
 
         match item_count {
+            // 16. If itemCount < actualDeleteCount, then
             ic if ic < actual_delete_count => {
+                //     a. Set k to actualStart.
+                //     b. Repeat, while k < (len - actualDeleteCount),
                 for k in actual_start..len - actual_delete_count {
+                    // i. Let from be ! ToString(𝔽(k + actualDeleteCount)).
                     let from = k + actual_delete_count;
+                    // ii. Let to be ! ToString(𝔽(k + itemCount)).
                     let to = k + item_count;
+                    // iii. Let fromPresent be ? HasProperty(O, from).
                     let from_present = this.has_field(from);
+                    // iv. If fromPresent is true, then
                     if from_present {
+                        // 1. Let fromValue be ? Get(O, from).
                         let from_value = this.get_field(from, context)?;
+                        // 2. Perform ? Set(O, to, fromValue, true).
                         let fv = DataDescriptor::new(
                             from_value,
                             Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
                         );
                         this.set_property(to, fv);
+                    // v. Else,
                     } else {
+                        // 1. Assert: fromPresent is false.
                         debug_assert!(!from_present);
-                        this.remove_property(to);
+                        // 2. Perform ? DeletePropertyOrThrow(O, to).
+                        this.delete_property_or_throw(to, context)?;
                     }
+                    // vi. Set k to k + 1.
                 }
+                // c. Set k to len.
+                // d. Repeat, while k > (len - actualDeleteCount + itemCount),
                 for k in ((len - actual_delete_count + item_count) + 1..=len).rev() {
-                    this.remove_property(k - 1);
+                    // i. Perform ? DeletePropertyOrThrow(O, ! ToString(𝔽(k - 1))).
+                    this.delete_property_or_throw(k - 1, context)?;
+                    // ii. Set k to k - 1.
                 }
             }
+            // 17. Else if itemCount > actualDeleteCount, then
             ic if ic > actual_delete_count => {
+                // a. Set k to (len - actualDeleteCount).
+                // b. Repeat, while k > actualStart,
                 for k in (actual_start + 1..=len - actual_delete_count).rev() {
+                    // i. Let from be ! ToString(𝔽(k + actualDeleteCount - 1)).
                     let from = k + actual_delete_count - 1;
+                    // ii. Let to be ! ToString(𝔽(k + itemCount - 1)).
                     let to = k + item_count - 1;
+                    // iii. Let fromPresent be ? HasProperty(O, from).
                     let from_present = this.has_field(from);
+                    // iv. If fromPresent is true, then
                     if from_present {
+                        // 1. Let fromValue be ? Get(O, from).
                         let from_value = this.get_field(from, context)?;
+                        // 2. Perform ? Set(O, to, fromValue, true).
                         let fv = DataDescriptor::new(
                             from_value,
                             Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
                         );
                         this.set_property(to, fv);
+                    // v. Else,
                     } else {
+                        // 1. Assert: fromPresent is false.
                         debug_assert!(!from_present);
-                        this.remove_property(to);
+                        // 2. Perform ? DeletePropertyOrThrow(O, to).
+                        this.delete_property_or_throw(to, context)?;
                     }
+                    // vi. Set k to k - 1.
                 }
             }
             _ => {}
         };
 
+        // 18. Set k to actualStart.
         let mut k = actual_start;
 
-        for item in items {
-            let prop = DataDescriptor::new(
-                item,
-                Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-            );
-            this.set_property(k, prop);
-            k += 1;
+        // 19. For each element E of items, do
+        if item_count > 0 {
+            let items = args.split_at(2).1;
+            for item in items {
+                // a. Perform ? Set(O, ! ToString(𝔽(k)), E, true).
+                let prop = DataDescriptor::new(
+                    item,
+                    Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
+                );
+                this.set_property(k, prop);
+                // b. Set k to k + 1.
+                k += 1;
+            }
         }
 
+        // 20. Perform ? Set(O, "length", 𝔽(len - actualDeleteCount + itemCount), true).
         let length = DataDescriptor::new(
             Value::from(len - actual_delete_count + item_count),
             Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
@@ -1834,6 +1884,7 @@ impl Array {
 
         this.set_property("length", length);
 
+        // 21. Return A.
         Ok(arr)
     }
 
diff --git a/boa/src/value/mod.rs b/boa/src/value/mod.rs
index a6fa89c65f4..6700ba4fc9f 100644
--- a/boa/src/value/mod.rs
+++ b/boa/src/value/mod.rs
@@ -442,6 +442,19 @@ impl Value {
         }
     }
 
+    pub fn delete_property_or_throw<Key>(&self, key: Key, context: &mut Context) -> Result<Value>
+    where
+        Key: Into<PropertyKey>,
+    {
+        debug_assert!(self.is_object());
+        // debug_assert!(self.get_property(key).is_some());
+        if self.remove_property(key) {
+            Ok(Value::from(true))
+        } else {
+            context.throw_type_error("Unable to delete property")
+        }
+    }
+
     /// Resolve the property in the object.
     ///
     /// A copy of the Property is returned.

From b51752486c3c5b259db034f24e4f50f9f551dde5 Mon Sep 17 00:00:00 2001
From: neeldug <5161147+neeldug@users.noreply.github.com>
Date: Fri, 30 Jul 2021 01:51:33 +0100
Subject: [PATCH 07/16] Cleanup due to merge

---
 boa/src/builtins/array/mod.rs | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index 69e7451a7e4..bac99f8b761 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1566,16 +1566,8 @@ impl Array {
         if len + insert_count - actual_delete_count > Number::MAX_SAFE_INTEGER as usize {
             return context.throw_type_error("Target splice exceeded max safe integer value");
         }
-
-        //temp until arrayspecies merges
-        if actual_delete_count >= u32::MAX as usize {
-            return context.throw_type_error("Target splice exceeded max safe integer value");
-        }
-        // -------------------------------
-
         // 11. Let A be ? ArraySpeciesCreate(O, actualDeleteCount).
         let arr = Self::array_species_create(&o, actual_delete_count as u32, context)?;
-
         // 12. Let k be 0.
         // 13. Repeat, while k < actualDeleteCount,
         for k in 0..actual_delete_count {

From 7212db43bf88539b6df1d08848d58c7e8776e0f0 Mon Sep 17 00:00:00 2001
From: neeldug <5161147+neeldug@users.noreply.github.com>
Date: Fri, 30 Jul 2021 01:51:33 +0100
Subject: [PATCH 08/16] Cleanup due to merge

---
 boa/src/builtins/array/mod.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index bac99f8b761..c9cdfed4253 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1745,7 +1745,6 @@ impl Array {
 
         // 11. Let A be ? ArraySpeciesCreate(O, actualDeleteCount).
         let arr = Self::array_species_create(&o, actual_delete_count as u32, context)?;
-
         // 12. Let k be 0.
         // 13. Repeat, while k < actualDeleteCount,
         for k in 0..actual_delete_count {

From 861462aa6a30b7f62d72288d42f245d9e4b056ce Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Fri, 30 Jul 2021 19:25:36 +0100
Subject: [PATCH 09/16] changes

---
 boa/src/builtins/array/mod.rs | 240 ++++------------------------------
 boa/src/value/mod.rs          |  26 ----
 2 files changed, 24 insertions(+), 242 deletions(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index c9cdfed4253..09049033bbc 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1522,7 +1522,7 @@ impl Array {
         // 1. Let O be ? ToObject(this value).
         let o = this.to_object(context)?;
         // 2. Let len be ? LengthOfArrayLike(O).
-        let len = this.get_field("length", context)?.to_length(context)?;
+        let len = o.length_of_array_like(context)?;
         // 3. Let relativeStart be ? ToIntegerOrInfinity(start).
         // 4. If relativeStart is -∞, let actualStart be 0.
         // 5. Else if relativeStart < 0, let actualStart be max(len + relativeStart, 0).
@@ -1531,8 +1531,8 @@ impl Array {
         // 7. If start is not present, then
         let insert_count = if args.get(0).is_none() || args.get(1).is_none() {
             // 7a. Let insertCount be 0.
-            // 8a. Let insertCount be 0.
             0
+        // 9. Else,
         } else {
             // 9a. Let insertCount be the number of elements in items.
             args.len()
@@ -1540,11 +1540,13 @@ impl Array {
         let actual_delete_count = if args.get(0).is_none() {
             // 7b. Let actualDeleteCount be 0.
             0
+            // 8. Else if deleteCount is not present, then
         } else if args.get(1).is_none() {
             // 8b. Let actualDeleteCount be len - actualStart.
             len - actual_start
+        // 9. Else,
         } else {
-            // 9b. Let dc be ? ToIntegerOrInfinity(deleteCount).
+            // b. Let dc be ? ToIntegerOrInfinity(deleteCount).
             let dc = args.get(1).ok_or(0)?.to_integer_or_infinity(context)?;
             // c. Let actualDeleteCount be the result of clamping dc between 0 and len - actualStart.
             let max = len - actual_start;
@@ -1562,205 +1564,26 @@ impl Array {
                 IntegerOrInfinity::NegativeInfinity => 0,
             }
         };
-        // 10. If len + insertCount - actualDeleteCount > 253 - 1, throw a TypeError exception.
-        if len + insert_count - actual_delete_count > Number::MAX_SAFE_INTEGER as usize {
-            return context.throw_type_error("Target splice exceeded max safe integer value");
-        }
-        // 11. Let A be ? ArraySpeciesCreate(O, actualDeleteCount).
-        let arr = Self::array_species_create(&o, actual_delete_count as u32, context)?;
-        // 12. Let k be 0.
-        // 13. Repeat, while k < actualDeleteCount,
-        for k in 0..actual_delete_count {
-            // a. Let from be ! ToString(𝔽(actualStart + k)).
-            // b. Let fromPresent be ? HasProperty(O, from).
-            let from_present = this.has_field(actual_start + k);
-            // c. If fromPresent is true, then
-            if from_present {
-                // i. Let fromValue be ? Get(O, from).
-                let from_value = this.get_field(actual_start + k, context)?;
-                // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(𝔽(k)), fromValue).
-                let fv = DataDescriptor::new(
-                    from_value,
-                    Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-                );
-                arr.set_property(actual_start + k, fv);
-            }
-            // d. Set k to k + 1.
-        }
-
-        // 14. Perform ? Set(A, "length", 𝔽(actualDeleteCount), true).
-        let acd = DataDescriptor::new(
-            Value::from(actual_delete_count),
-            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-        );
-
-        arr.set_property("length", acd);
-
-        // 15. Let itemCount be the number of elements in items.
-        let item_count = args.len().saturating_sub(2);
-
-        match item_count {
-            // 16. If itemCount < actualDeleteCount, then
-            ic if ic < actual_delete_count => {
-                //     a. Set k to actualStart.
-                //     b. Repeat, while k < (len - actualDeleteCount),
-                for k in actual_start..len - actual_delete_count {
-                    // i. Let from be ! ToString(𝔽(k + actualDeleteCount)).
-                    let from = k + actual_delete_count;
-                    // ii. Let to be ! ToString(𝔽(k + itemCount)).
-                    let to = k + item_count;
-                    // iii. Let fromPresent be ? HasProperty(O, from).
-                    let from_present = this.has_field(from);
-                    // iv. If fromPresent is true, then
-                    if from_present {
-                        // 1. Let fromValue be ? Get(O, from).
-                        let from_value = this.get_field(from, context)?;
-                        // 2. Perform ? Set(O, to, fromValue, true).
-                        let fv = DataDescriptor::new(
-                            from_value,
-                            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-                        );
-                        this.set_property(to, fv);
-                    // v. Else,
-                    } else {
-                        // 1. Assert: fromPresent is false.
-                        debug_assert!(!from_present);
-                        // 2. Perform ? DeletePropertyOrThrow(O, to).
-                        this.delete_property_or_throw(to, context)?;
-                    }
-                    // vi. Set k to k + 1.
-                }
-                // c. Set k to len.
-                // d. Repeat, while k > (len - actualDeleteCount + itemCount),
-                for k in ((len - actual_delete_count + item_count) + 1..=len).rev() {
-                    // i. Perform ? DeletePropertyOrThrow(O, ! ToString(𝔽(k - 1))).
-                    this.delete_property_or_throw(k - 1, context)?;
-                    // ii. Set k to k - 1.
-                }
-            }
-            // 17. Else if itemCount > actualDeleteCount, then
-            ic if ic > actual_delete_count => {
-                // a. Set k to (len - actualDeleteCount).
-                // b. Repeat, while k > actualStart,
-                for k in (actual_start + 1..=len - actual_delete_count).rev() {
-                    // i. Let from be ! ToString(𝔽(k + actualDeleteCount - 1)).
-                    let from = k + actual_delete_count - 1;
-                    // ii. Let to be ! ToString(𝔽(k + itemCount - 1)).
-                    let to = k + item_count - 1;
-                    // iii. Let fromPresent be ? HasProperty(O, from).
-                    let from_present = this.has_field(from);
-                    // iv. If fromPresent is true, then
-                    if from_present {
-                        // 1. Let fromValue be ? Get(O, from).
-                        let from_value = this.get_field(from, context)?;
-                        // 2. Perform ? Set(O, to, fromValue, true).
-                        let fv = DataDescriptor::new(
-                            from_value,
-                            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-                        );
-                        this.set_property(to, fv);
-                    // v. Else,
-                    } else {
-                        // 1. Assert: fromPresent is false.
-                        debug_assert!(!from_present);
-                        // 2. Perform ? DeletePropertyOrThrow(O, to).
-                        this.delete_property_or_throw(to, context)?;
-                    }
-                    // vi. Set k to k - 1.
-                }
-            }
-            _ => {}
-        };
-
-        // 18. Set k to actualStart.
-        let mut k = actual_start;
-
-        // 19. For each element E of items, do
-        if item_count > 0 {
-            let items = args.split_at(2).1;
-            for item in items {
-                // a. Perform ? Set(O, ! ToString(𝔽(k)), E, true).
-                let prop = DataDescriptor::new(
-                    item,
-                    Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-                );
-                this.set_property(k, prop);
-                // b. Set k to k + 1.
-                k += 1;
-            }
-        }
-
-        // 20. Perform ? Set(O, "length", 𝔽(len - actualDeleteCount + itemCount), true).
-        let length = DataDescriptor::new(
-            Value::from(len - actual_delete_count + item_count),
-            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-        );
-
-        this.set_property("length", length);
-
-        // 21. Return A.
-        Ok(arr)
-    }
-
-    pub(crate) fn splice(this: &Value, args: &[Value], context: &mut Context) -> Result<Value> {
-        let o = this.to_object(context)?;
-        let len = this.get_field("length", context)?.to_length(context)?;
-        let actual_start = Self::get_relative_start(context, args.get(0), len)?;
-        let insert_count = if args.get(0).is_none() || args.get(1).is_none() {
-            0
-        } else {
-            args.len()
-        };
-        let actual_delete_count = if args.get(0).is_none() {
-            0
-        } else if args.get(1).is_none() {
-            len - actual_start
-        } else {
-            let dc = args.get(1).ok_or(0)?.to_integer_or_infinity(context)?;
-            let max = len - actual_start;
-            match dc {
-                IntegerOrInfinity::Integer(i) => {
-                    if i < 0 {
-                        0
-                    } else if i as usize > max {
-                        max
-                    } else {
-                        i as usize
-                    }
-                }
-                IntegerOrInfinity::PositiveInfinity => max,
-                IntegerOrInfinity::NegativeInfinity => 0,
-            }
-        };
 
+        // 10. If len + insertCount - actualDeleteCount > 253 - 1, throw a TypeError exception.
         if len + insert_count - actual_delete_count > Number::MAX_SAFE_INTEGER as usize {
             return context.throw_type_error("Target splice exceeded max safe integer value");
         }
 
-        //temp until arrayspecies merges
-        if actual_delete_count >= u32::MAX as usize {
-            return context.throw_type_error("Target splice exceeded max safe integer value");
-        }
-        // -------------------------------
-
         // 11. Let A be ? ArraySpeciesCreate(O, actualDeleteCount).
-        let arr = Self::array_species_create(&o, actual_delete_count as u32, context)?;
+        let arr = Self::array_species_create(&o, actual_delete_count, context)?;
         // 12. Let k be 0.
         // 13. Repeat, while k < actualDeleteCount,
         for k in 0..actual_delete_count {
             // a. Let from be ! ToString(𝔽(actualStart + k)).
             // b. Let fromPresent be ? HasProperty(O, from).
-            let from_present = this.has_field(actual_start + k);
+            let from_present = o.has_property(actual_start + k)?;
             // c. If fromPresent is true, then
             if from_present {
                 // i. Let fromValue be ? Get(O, from).
-                let from_value = this.get_field(actual_start + k, context)?;
+                let from_value = o.get(actual_start + k, context)?;
                 // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(𝔽(k)), fromValue).
-                let fv = DataDescriptor::new(
-                    from_value,
-                    Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-                );
-                arr.set_property(actual_start + k, fv);
+                arr.create_data_property_or_throw(actual_start + k, from_value, context)?;
             }
             // d. Set k to k + 1.
         }
@@ -1773,6 +1596,8 @@ impl Array {
 
         arr.set_property("length", acd);
 
+        arr.set("length", actual_delete_count, true, context)?;
+
         // 15. Let itemCount be the number of elements in items.
         let item_count = args.len().saturating_sub(2);
 
@@ -1787,23 +1612,19 @@ impl Array {
                     // ii. Let to be ! ToString(𝔽(k + itemCount)).
                     let to = k + item_count;
                     // iii. Let fromPresent be ? HasProperty(O, from).
-                    let from_present = this.has_field(from);
+                    let from_present = o.has_property(from, context)?;
                     // iv. If fromPresent is true, then
                     if from_present {
                         // 1. Let fromValue be ? Get(O, from).
-                        let from_value = this.get_field(from, context)?;
+                        let from_value = o.get(from, context)?;
                         // 2. Perform ? Set(O, to, fromValue, true).
-                        let fv = DataDescriptor::new(
-                            from_value,
-                            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-                        );
-                        this.set_property(to, fv);
+                        o.set(to, from_value, true, context)?;
                     // v. Else,
                     } else {
                         // 1. Assert: fromPresent is false.
                         debug_assert!(!from_present);
                         // 2. Perform ? DeletePropertyOrThrow(O, to).
-                        this.delete_property_or_throw(to, context)?;
+                        o.delete_property_or_throw(to, context)?;
                     }
                     // vi. Set k to k + 1.
                 }
@@ -1811,7 +1632,7 @@ impl Array {
                 // d. Repeat, while k > (len - actualDeleteCount + itemCount),
                 for k in ((len - actual_delete_count + item_count) + 1..=len).rev() {
                     // i. Perform ? DeletePropertyOrThrow(O, ! ToString(𝔽(k - 1))).
-                    this.delete_property_or_throw(k - 1, context)?;
+                    o.delete_property_or_throw(k - 1, context)?;
                     // ii. Set k to k - 1.
                 }
             }
@@ -1825,23 +1646,19 @@ impl Array {
                     // ii. Let to be ! ToString(𝔽(k + itemCount - 1)).
                     let to = k + item_count - 1;
                     // iii. Let fromPresent be ? HasProperty(O, from).
-                    let from_present = this.has_field(from);
+                    let from_present = o.has_property(from, context)?;
                     // iv. If fromPresent is true, then
                     if from_present {
                         // 1. Let fromValue be ? Get(O, from).
-                        let from_value = this.get_field(from, context)?;
+                        let from_value = o.get(from, context)?;
                         // 2. Perform ? Set(O, to, fromValue, true).
-                        let fv = DataDescriptor::new(
-                            from_value,
-                            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-                        );
-                        this.set_property(to, fv);
+                        o.set(to, from_value, true, context)?;
                     // v. Else,
                     } else {
                         // 1. Assert: fromPresent is false.
                         debug_assert!(!from_present);
                         // 2. Perform ? DeletePropertyOrThrow(O, to).
-                        this.delete_property_or_throw(to, context)?;
+                        o.delete_property_or_throw(to, context)?;
                     }
                     // vi. Set k to k - 1.
                 }
@@ -1857,26 +1674,17 @@ impl Array {
             let items = args.split_at(2).1;
             for item in items {
                 // a. Perform ? Set(O, ! ToString(𝔽(k)), E, true).
-                let prop = DataDescriptor::new(
-                    item,
-                    Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-                );
-                this.set_property(k, prop);
+                o.set(k, item, true, context)?;
                 // b. Set k to k + 1.
                 k += 1;
             }
         }
 
         // 20. Perform ? Set(O, "length", 𝔽(len - actualDeleteCount + itemCount), true).
-        let length = DataDescriptor::new(
-            Value::from(len - actual_delete_count + item_count),
-            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-        );
-
-        this.set_property("length", length);
+        o.set("length", len - actual_delete_count + item_count, true, context)?;
 
         // 21. Return A.
-        Ok(arr)
+        Ok(Value::from(arr))
     }
 
     /// `Array.prototype.filter( callback, [ thisArg ] )`
diff --git a/boa/src/value/mod.rs b/boa/src/value/mod.rs
index 6700ba4fc9f..9c9a26a6dea 100644
--- a/boa/src/value/mod.rs
+++ b/boa/src/value/mod.rs
@@ -429,32 +429,6 @@ impl Value {
         self.as_object().map(|x| x.remove(&key.into())).is_some()
     }
 
-    pub fn delete_property_or_throw<Key>(&self, key: Key, context: &mut Context) -> Result<Value>
-    where
-        Key: Into<PropertyKey>,
-    {
-        debug_assert!(self.is_object());
-        // debug_assert!(self.get_property(key).is_some());
-        if self.remove_property(key) {
-            Ok(Value::from(true))
-        } else {
-            context.throw_type_error("Unable to delete property")
-        }
-    }
-
-    pub fn delete_property_or_throw<Key>(&self, key: Key, context: &mut Context) -> Result<Value>
-    where
-        Key: Into<PropertyKey>,
-    {
-        debug_assert!(self.is_object());
-        // debug_assert!(self.get_property(key).is_some());
-        if self.remove_property(key) {
-            Ok(Value::from(true))
-        } else {
-            context.throw_type_error("Unable to delete property")
-        }
-    }
-
     /// Resolve the property in the object.
     ///
     /// A copy of the Property is returned.

From 824b06b8b55d394f7d2f7c7757322402f5def24a Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Fri, 30 Jul 2021 19:30:14 +0100
Subject: [PATCH 10/16] final fixes

---
 boa/src/builtins/array/mod.rs | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index 09049033bbc..bb2e6910eab 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1577,7 +1577,7 @@ impl Array {
         for k in 0..actual_delete_count {
             // a. Let from be ! ToString(𝔽(actualStart + k)).
             // b. Let fromPresent be ? HasProperty(O, from).
-            let from_present = o.has_property(actual_start + k)?;
+            let from_present = o.has_property(actual_start + k, context)?;
             // c. If fromPresent is true, then
             if from_present {
                 // i. Let fromValue be ? Get(O, from).
@@ -1589,13 +1589,6 @@ impl Array {
         }
 
         // 14. Perform ? Set(A, "length", 𝔽(actualDeleteCount), true).
-        let acd = DataDescriptor::new(
-            Value::from(actual_delete_count),
-            Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::PERMANENT,
-        );
-
-        arr.set_property("length", acd);
-
         arr.set("length", actual_delete_count, true, context)?;
 
         // 15. Let itemCount be the number of elements in items.

From 68cdfbfd9672e66187883d1ab3195b0373795713 Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Thu, 5 Aug 2021 18:24:18 +0100
Subject: [PATCH 11/16] fix clippy

---
 boa/src/builtins/array/mod.rs | 11 ++++++++---
 boa_tester/src/exec/mod.rs    |  4 ++--
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index bb2e6910eab..f94e422c57a 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -167,7 +167,7 @@ impl Array {
                 // i. Let intLen be ! ToUint32(len).
                 let int_len = len.to_u32(context).unwrap();
                 // ii. If SameValueZero(intLen, len) is false, throw a RangeError exception.
-                if !Value::same_value_zero(&int_len.into(), &len) {
+                if !Value::same_value_zero(&int_len.into(), len) {
                     return Err(context.construct_range_error("invalid array length"));
                 }
                 int_len
@@ -1623,7 +1623,7 @@ impl Array {
                 }
                 // c. Set k to len.
                 // d. Repeat, while k > (len - actualDeleteCount + itemCount),
-                for k in ((len - actual_delete_count + item_count) + 1..=len).rev() {
+                for k in ((len - actual_delete_count + item_count + 1)..=len).rev() {
                     // i. Perform ? DeletePropertyOrThrow(O, ! ToString(𝔽(k - 1))).
                     o.delete_property_or_throw(k - 1, context)?;
                     // ii. Set k to k - 1.
@@ -1674,7 +1674,12 @@ impl Array {
         }
 
         // 20. Perform ? Set(O, "length", 𝔽(len - actualDeleteCount + itemCount), true).
-        o.set("length", len - actual_delete_count + item_count, true, context)?;
+        o.set(
+            "length",
+            len - actual_delete_count + item_count,
+            true,
+            context,
+        )?;
 
         // 21. Return A.
         Ok(Value::from(arr))
diff --git a/boa_tester/src/exec/mod.rs b/boa_tester/src/exec/mod.rs
index 82634a69b84..b8be3404396 100644
--- a/boa_tester/src/exec/mod.rs
+++ b/boa_tester/src/exec/mod.rs
@@ -137,7 +137,7 @@ impl Test {
                 Outcome::Positive => {
                     // TODO: implement async and add `harness/doneprintHandle.js` to the includes.
 
-                    match self.set_up_env(&harness, strict) {
+                    match self.set_up_env(harness, strict) {
                         Ok(mut context) => {
                             let res = context.eval(&self.content.as_ref());
 
@@ -183,7 +183,7 @@ impl Test {
                     if let Err(e) = parse(&self.content.as_ref(), strict) {
                         (false, format!("Uncaught {}", e))
                     } else {
-                        match self.set_up_env(&harness, strict) {
+                        match self.set_up_env(harness, strict) {
                             Ok(mut context) => match context.eval(&self.content.as_ref()) {
                                 Ok(res) => (false, format!("{}", res.display())),
                                 Err(e) => {

From bcf71eebefe190c92b26933f72a41958e21d26b7 Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Fri, 6 Aug 2021 19:16:40 +0100
Subject: [PATCH 12/16] changes

---
 boa/src/builtins/array/mod.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index f94e422c57a..768f49c902a 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1531,11 +1531,13 @@ impl Array {
         // 7. If start is not present, then
         let insert_count = if args.get(0).is_none() || args.get(1).is_none() {
             // 7a. Let insertCount be 0.
+            // 8. Else if deleteCount is not present, then
+            // a. Let insertCount be 0.
             0
         // 9. Else,
         } else {
             // 9a. Let insertCount be the number of elements in items.
-            args.len()
+            args.len().saturating_sub(2)
         };
         let actual_delete_count = if args.get(0).is_none() {
             // 7b. Let actualDeleteCount be 0.
@@ -1599,7 +1601,7 @@ impl Array {
             ic if ic < actual_delete_count => {
                 //     a. Set k to actualStart.
                 //     b. Repeat, while k < (len - actualDeleteCount),
-                for k in actual_start..len - actual_delete_count {
+                for k in actual_start..(len - actual_delete_count) {
                     // i. Let from be ! ToString(𝔽(k + actualDeleteCount)).
                     let from = k + actual_delete_count;
                     // ii. Let to be ! ToString(𝔽(k + itemCount)).

From 1a0f3395efb2698654c02e2dcf3463a650a3539f Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Sat, 4 Sep 2021 13:44:34 +0100
Subject: [PATCH 13/16] (cleanup) fix formatting and unwrap

---
 boa/src/builtins/array/mod.rs | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index 768f49c902a..93aa969e02f 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1512,12 +1512,12 @@ impl Array {
         new_array.set_field("length", Value::from(new_array_len), true, context)?;
         Ok(new_array)
     }
+
     /// `Array.prototype.splice ( start, [deleteCount[, ...items]] )`
     ///
     /// Splices an array by following
     /// The deleteCount elements of the array starting at integer index start are replaced by the elements of items.
     /// An Array object containing the deleted elements (if any) is returned.
-
     pub(crate) fn splice(this: &Value, args: &[Value], context: &mut Context) -> Result<Value> {
         // 1. Let O be ? ToObject(this value).
         let o = this.to_object(context)?;
@@ -1549,7 +1549,11 @@ impl Array {
         // 9. Else,
         } else {
             // b. Let dc be ? ToIntegerOrInfinity(deleteCount).
-            let dc = args.get(1).ok_or(0)?.to_integer_or_infinity(context)?;
+            let dc = args
+                .get(1)
+                .cloned()
+                .unwrap_or_default()
+                .to_integer_or_infinity(context)?;
             // c. Let actualDeleteCount be the result of clamping dc between 0 and len - actualStart.
             let max = len - actual_start;
             match dc {

From e992b9227ef55362f1b2a4b260930b42c87a7df3 Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Sat, 4 Sep 2021 15:00:21 +0100
Subject: [PATCH 14/16] update submodule

---
 test262 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test262 b/test262
index e793512b55c..2c4f2665ec8 160000
--- a/test262
+++ b/test262
@@ -1 +1 @@
-Subproject commit e793512b55c199de6abc392d1be4de7325dae544
+Subproject commit 2c4f2665ec86f01bff7e42d3a5b54c9a09f9a362

From 7542ffb8eb6973549afa6f8b7a224491e982a51a Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Sat, 4 Sep 2021 17:53:09 +0100
Subject: [PATCH 15/16] (refactor) cleaning up and improving readability

---
 boa/src/builtins/array/mod.rs | 51 ++++++++++++++++-------------------
 1 file changed, 23 insertions(+), 28 deletions(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index aa5060e1730..bcac302f730 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1797,13 +1797,17 @@ impl Array {
         let o = this.to_object(context)?;
         // 2. Let len be ? LengthOfArrayLike(O).
         let len = o.length_of_array_like(context)?;
+
+        let start = args.get(0);
+        let delete_count = args.get(1);
+        let items = args.get(2..).unwrap_or(&[]);
         // 3. Let relativeStart be ? ToIntegerOrInfinity(start).
         // 4. If relativeStart is -∞, let actualStart be 0.
         // 5. Else if relativeStart < 0, let actualStart be max(len + relativeStart, 0).
         // 6. Else, let actualStart be min(relativeStart, len).
-        let actual_start = Self::get_relative_start(context, args.get(0), len)?;
+        let actual_start = Self::get_relative_start(context, start, len)?;
         // 7. If start is not present, then
-        let insert_count = if args.get(0).is_none() || args.get(1).is_none() {
+        let insert_count = if start.is_none() || delete_count.is_none() {
             // 7a. Let insertCount be 0.
             // 8. Else if deleteCount is not present, then
             // a. Let insertCount be 0.
@@ -1811,41 +1815,32 @@ impl Array {
         // 9. Else,
         } else {
             // 9a. Let insertCount be the number of elements in items.
-            args.len().saturating_sub(2)
+            items.len()
         };
-        let actual_delete_count = if args.get(0).is_none() {
+        let actual_delete_count = if start.is_none() {
             // 7b. Let actualDeleteCount be 0.
             0
             // 8. Else if deleteCount is not present, then
-        } else if args.get(1).is_none() {
+        } else if delete_count.is_none() {
             // 8b. Let actualDeleteCount be len - actualStart.
             len - actual_start
         // 9. Else,
         } else {
             // b. Let dc be ? ToIntegerOrInfinity(deleteCount).
-            let dc = args
-                .get(1)
+            let dc = delete_count
                 .cloned()
                 .unwrap_or_default()
                 .to_integer_or_infinity(context)?;
             // c. Let actualDeleteCount be the result of clamping dc between 0 and len - actualStart.
             let max = len - actual_start;
             match dc {
-                IntegerOrInfinity::Integer(i) => {
-                    if i < 0 {
-                        0
-                    } else if i as usize > max {
-                        max
-                    } else {
-                        i as usize
-                    }
-                }
+                IntegerOrInfinity::Integer(i) => (i as usize).clamp(0, max),
                 IntegerOrInfinity::PositiveInfinity => max,
                 IntegerOrInfinity::NegativeInfinity => 0,
             }
         };
 
-        // 10. If len + insertCount - actualDeleteCount > 253 - 1, throw a TypeError exception.
+        // 10. If len + insertCount - actualDeleteCount > 2^53 - 1, throw a TypeError exception.
         if len + insert_count - actual_delete_count > Number::MAX_SAFE_INTEGER as usize {
             return context.throw_type_error("Target splice exceeded max safe integer value");
         }
@@ -1863,7 +1858,7 @@ impl Array {
                 // i. Let fromValue be ? Get(O, from).
                 let from_value = o.get(actual_start + k, context)?;
                 // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(𝔽(k)), fromValue).
-                arr.create_data_property_or_throw(actual_start + k, from_value, context)?;
+                arr.create_data_property_or_throw(k, from_value, context)?;
             }
             // d. Set k to k + 1.
         }
@@ -1872,11 +1867,11 @@ impl Array {
         arr.set("length", actual_delete_count, true, context)?;
 
         // 15. Let itemCount be the number of elements in items.
-        let item_count = args.len().saturating_sub(2);
+        let item_count = items.len();
 
-        match item_count {
+        match item_count.cmp(&actual_delete_count) {
             // 16. If itemCount < actualDeleteCount, then
-            ic if ic < actual_delete_count => {
+            Ordering::Less => {
                 //     a. Set k to actualStart.
                 //     b. Repeat, while k < (len - actualDeleteCount),
                 for k in actual_start..(len - actual_delete_count) {
@@ -1910,7 +1905,7 @@ impl Array {
                 }
             }
             // 17. Else if itemCount > actualDeleteCount, then
-            ic if ic > actual_delete_count => {
+            Ordering::Greater => {
                 // a. Set k to (len - actualDeleteCount).
                 // b. Repeat, while k > actualStart,
                 for k in (actual_start + 1..=len - actual_delete_count).rev() {
@@ -1936,20 +1931,20 @@ impl Array {
                     // vi. Set k to k - 1.
                 }
             }
-            _ => {}
+            Ordering::Equal => {}
         };
 
         // 18. Set k to actualStart.
-        let mut k = actual_start;
-
         // 19. For each element E of items, do
         if item_count > 0 {
-            let items = args.split_at(2).1;
-            for item in items {
+            for (k, item) in items
+                .iter()
+                .enumerate()
+                .map(|(i, val)| (i + actual_start, val))
+            {
                 // a. Perform ? Set(O, ! ToString(𝔽(k)), E, true).
                 o.set(k, item, true, context)?;
                 // b. Set k to k + 1.
-                k += 1;
             }
         }
 

From 09a71db0ee69d2acda912b5e19a72cc69fc8448f Mon Sep 17 00:00:00 2001
From: nd419 <5161147+neeldug@users.noreply.github.com>
Date: Sun, 5 Sep 2021 23:10:35 +0100
Subject: [PATCH 16/16] fixing weirdness in spec

---
 boa/src/builtins/array/mod.rs | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs
index bcac302f730..1a4bebaa44f 100644
--- a/boa/src/builtins/array/mod.rs
+++ b/boa/src/builtins/array/mod.rs
@@ -1898,9 +1898,9 @@ impl Array {
                 }
                 // c. Set k to len.
                 // d. Repeat, while k > (len - actualDeleteCount + itemCount),
-                for k in ((len - actual_delete_count + item_count + 1)..=len).rev() {
+                for k in ((len - actual_delete_count + item_count)..len).rev() {
                     // i. Perform ? DeletePropertyOrThrow(O, ! ToString(𝔽(k - 1))).
-                    o.delete_property_or_throw(k - 1, context)?;
+                    o.delete_property_or_throw(k, context)?;
                     // ii. Set k to k - 1.
                 }
             }
@@ -1908,11 +1908,11 @@ impl Array {
             Ordering::Greater => {
                 // a. Set k to (len - actualDeleteCount).
                 // b. Repeat, while k > actualStart,
-                for k in (actual_start + 1..=len - actual_delete_count).rev() {
+                for k in (actual_start..len - actual_delete_count).rev() {
                     // i. Let from be ! ToString(𝔽(k + actualDeleteCount - 1)).
-                    let from = k + actual_delete_count - 1;
+                    let from = k + actual_delete_count;
                     // ii. Let to be ! ToString(𝔽(k + itemCount - 1)).
-                    let to = k + item_count - 1;
+                    let to = k + item_count;
                     // iii. Let fromPresent be ? HasProperty(O, from).
                     let from_present = o.has_property(from, context)?;
                     // iv. If fromPresent is true, then