Skip to content

Commit

Permalink
Enable mutation on closure Captures
Browse files Browse the repository at this point in the history
  • Loading branch information
jedel1043 committed Oct 10, 2021
1 parent d6d4f4e commit 7a17da0
Show file tree
Hide file tree
Showing 37 changed files with 918 additions and 1,147 deletions.
88 changes: 42 additions & 46 deletions boa/src/builtins/array/array_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,57 +62,53 @@ impl ArrayIterator {
///
/// [spec]: https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
pub(crate) fn next(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
if let JsValue::Object(ref object) = this {
let mut object = object.borrow_mut();
if let Some(array_iterator) = object.as_array_iterator_mut() {
let index = array_iterator.next_index;
if array_iterator.done {
return Ok(create_iter_result_object(
JsValue::undefined(),
true,
context,
));
}
let mut array_iterator = this.as_object().map(|obj| obj.borrow_mut());
let array_iterator = array_iterator
.as_mut()
.and_then(|obj| obj.as_array_iterator_mut())
.ok_or_else(|| context.construct_type_error("`this` is not an ArrayIterator"))?;
let index = array_iterator.next_index;
if array_iterator.done {
return Ok(create_iter_result_object(
JsValue::undefined(),
true,
context,
));
}

let len = if let Some(f) = array_iterator.array.borrow().as_typed_array() {
if f.is_detached() {
return context.throw_type_error(
"Cannot get value from typed array that has a detached array buffer",
);
}
let len = if let Some(f) = array_iterator.array.borrow().as_typed_array() {
if f.is_detached() {
return context.throw_type_error(
"Cannot get value from typed array that has a detached array buffer",
);
}

f.array_length()
} else {
array_iterator.array.length_of_array_like(context)?
};
f.array_length()
} else {
array_iterator.array.length_of_array_like(context)?
};

if index >= len {
array_iterator.done = true;
return Ok(create_iter_result_object(
JsValue::undefined(),
true,
context,
));
}
array_iterator.next_index = index + 1;
return match array_iterator.kind {
PropertyNameKind::Key => {
Ok(create_iter_result_object(index.into(), false, context))
}
PropertyNameKind::Value => {
let element_value = array_iterator.array.get(index, context)?;
Ok(create_iter_result_object(element_value, false, context))
}
PropertyNameKind::KeyAndValue => {
let element_value = array_iterator.array.get(index, context)?;
let result =
Array::create_array_from_list([index.into(), element_value], context);
Ok(create_iter_result_object(result.into(), false, context))
}
};
if index >= len {
array_iterator.done = true;
return Ok(create_iter_result_object(
JsValue::undefined(),
true,
context,
));
}
array_iterator.next_index = index + 1;
match array_iterator.kind {
PropertyNameKind::Key => Ok(create_iter_result_object(index.into(), false, context)),
PropertyNameKind::Value => {
let element_value = array_iterator.array.get(index, context)?;
Ok(create_iter_result_object(element_value, false, context))
}
PropertyNameKind::KeyAndValue => {
let element_value = array_iterator.array.get(index, context)?;
let result = Array::create_array_from_list([index.into(), element_value], context);
Ok(create_iter_result_object(result.into(), false, context))
}
}
context.throw_type_error("`this` is not an ArrayIterator")
}

/// Create the %ArrayIteratorPrototype% object
Expand Down
138 changes: 46 additions & 92 deletions boa/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,14 +354,12 @@ impl Array {
}

// 7. If IsConstructor(C) is false, throw a TypeError exception.
if let Some(c) = c.as_object() {
if !c.is_constructor() {
return Err(context.construct_type_error("Symbol.species must be a constructor"));
}
if let Some(c) = c.as_constructor() {
// 8. Return ? Construct(C, « 𝔽(length) »).
Ok(
c.construct(&[JsValue::new(length)], &c.clone().into(), context)?
.as_object()
.cloned()
.unwrap(),
)
} else {
Expand Down Expand Up @@ -412,10 +410,12 @@ impl Array {
/// [spec]: https://tc39.es/ecma262/#sec-array.isarray
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
pub(crate) fn is_array(_: &JsValue, args: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
match args.get(0).and_then(|x| x.as_object()) {
Some(object) => Ok(JsValue::new(object.borrow().is_array())),
None => Ok(JsValue::new(false)),
}
Ok(args
.get_or_undefined(0)
.as_object()
.map(|obj| obj.borrow().is_array())
.unwrap_or_default()
.into())
}

/// `Array.of(...items)`
Expand All @@ -439,10 +439,11 @@ impl Array {
// a. Let A be ? Construct(C, « lenNumber »).
// 5. Else,
// a. Let A be ? ArrayCreate(len).
let a = match this.as_object() {
Some(object) if object.is_constructor() => object
let a = match this.as_constructor() {
Some(constructor) => constructor
.construct(&[len.into()], this, context)?
.as_object()
.cloned()
.ok_or_else(|| {
context.construct_type_error("object constructor didn't return an object")
})?,
Expand Down Expand Up @@ -683,15 +684,9 @@ impl Array {
// 2. Let len be ? LengthOfArrayLike(O).
let len = o.length_of_array_like(context)?;
// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
let callback = if let Some(arg) = args
.get(0)
.and_then(JsValue::as_object)
.filter(JsObject::is_callable)
{
arg
} else {
return context.throw_type_error("Array.prototype.forEach: invalid callback function");
};
let callback = args.get_or_undefined(0).as_callable().ok_or_else(|| {
context.construct_type_error("Array.prototype.forEach: invalid callback function")
})?;
// 4. Let k be 0.
// 5. Repeat, while k < len,
for k in 0..len {
Expand Down Expand Up @@ -792,7 +787,7 @@ impl Array {
let func = array.get("join", context)?;
// 3. If IsCallable(func) is false, set func to the intrinsic function %Object.prototype.toString%.
// 4. Return ? Call(func, array).
if let Some(func) = func.as_object().filter(JsObject::is_callable) {
if let Some(func) = func.as_callable() {
func.call(&array.into(), &[], context)
} else {
crate::builtins::object::Object::to_string(&array.into(), &[], context)
Expand Down Expand Up @@ -1030,15 +1025,9 @@ impl Array {
// 2. Let len be ? LengthOfArrayLike(O).
let len = o.length_of_array_like(context)?;
// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
let callback = if let Some(arg) = args
.get(0)
.and_then(JsValue::as_object)
.filter(JsObject::is_callable)
{
arg
} else {
return context.throw_type_error("Array.prototype.every: callback is not callable");
};
let callback = args.get_or_undefined(0).as_callable().ok_or_else(|| {
context.construct_type_error("Array.prototype.every: callback is not callable")
})?;

let this_arg = args.get_or_undefined(1);

Expand Down Expand Up @@ -1088,13 +1077,9 @@ impl Array {
// 2. Let len be ? LengthOfArrayLike(O).
let len = o.length_of_array_like(context)?;
// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
let callback = args.get_or_undefined(0);
let callback = match callback {
JsValue::Object(obj) if obj.is_callable() => obj,
_ => {
return context.throw_type_error("Array.prototype.map: Callbackfn is not callable")
}
};
let callback = args.get_or_undefined(0).as_callable().ok_or_else(|| {
context.construct_type_error("Array.prototype.map: Callbackfn is not callable")
})?;

// 4. Let A be ? ArraySpeciesCreate(O, len).
let a = Self::array_species_create(&o, len, context)?;
Expand Down Expand Up @@ -1300,12 +1285,9 @@ impl Array {
let len = o.length_of_array_like(context)?;

// 3. If IsCallable(predicate) is false, throw a TypeError exception.
let predicate = match args.get(0).and_then(JsValue::as_object) {
Some(predicate) if predicate.is_callable() => predicate,
_ => {
return context.throw_type_error("Array.prototype.find: predicate is not callable")
}
};
let predicate = args.get_or_undefined(0).as_callable().ok_or_else(|| {
context.construct_type_error("Array.prototype.find: predicate is not callable")
})?;

let this_arg = args.get_or_undefined(1);

Expand Down Expand Up @@ -1360,13 +1342,9 @@ impl Array {
let len = o.length_of_array_like(context)?;

// 3. If IsCallable(predicate) is false, throw a TypeError exception.
let predicate = match args.get(0).and_then(JsValue::as_object) {
Some(predicate) if predicate.is_callable() => predicate,
_ => {
return context
.throw_type_error("Array.prototype.reduce: predicate is not callable")
}
};
let predicate = args.get_or_undefined(0).as_callable().ok_or_else(|| {
context.construct_type_error("Array.prototype.reduce: predicate is not callable")
})?;

let this_arg = args.get_or_undefined(1);

Expand Down Expand Up @@ -1472,11 +1450,9 @@ impl Array {
let source_len = o.length_of_array_like(context)?;

// 3. If ! IsCallable(mapperFunction) is false, throw a TypeError exception.
let mapper_function = args.get_or_undefined(0);
let mapper_function = match mapper_function {
JsValue::Object(obj) if obj.is_callable() => obj,
_ => return context.throw_type_error("flatMap mapper function is not callable"),
};
let mapper_function = args.get_or_undefined(0).as_callable().ok_or_else(|| {
context.construct_type_error("flatMap mapper function is not callable")
})?;

// 4. Let A be ? ArraySpeciesCreate(O, 0).
let a = Self::array_species_create(&o, 0, context)?;
Expand Down Expand Up @@ -1578,7 +1554,7 @@ impl Array {
// 4. Set targetIndex to ? FlattenIntoArray(target, element, elementLen, targetIndex, newDepth)
target_index = Self::flatten_into_array(
target,
&element,
element,
element_len as u64,
target_index,
new_depth,
Expand Down Expand Up @@ -2003,21 +1979,11 @@ impl Array {
let length = o.length_of_array_like(context)?;

// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
let callback = args
.get(0)
.map(|a| a.to_object(context))
.transpose()?
.ok_or_else(|| {
context.construct_type_error(
"missing argument 0 when calling function Array.prototype.filter",
)
})?;
let callback = args.get_or_undefined(0).as_callable().ok_or_else(|| {
context.construct_type_error("Array.prototype.filter: `callback` must be callable")
})?;
let this_arg = args.get_or_undefined(1);

if !callback.is_callable() {
return context.throw_type_error("the callback must be callable");
}

// 4. Let A be ? ArraySpeciesCreate(O, 0).
let a = Self::array_species_create(&o, 0, context)?;

Expand Down Expand Up @@ -2077,15 +2043,9 @@ impl Array {
// 2. Let len be ? LengthOfArrayLike(O).
let len = o.length_of_array_like(context)?;
// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
let callback = if let Some(arg) = args
.get(0)
.and_then(JsValue::as_object)
.filter(JsObject::is_callable)
{
arg
} else {
return context.throw_type_error("Array.prototype.some: callback is not callable");
};
let callback = args.get_or_undefined(0).as_callable().ok_or_else(|| {
context.construct_type_error("Array.prototype.some: callback is not callable")
})?;

// 4. Let k be 0.
// 5. Repeat, while k < len,
Expand Down Expand Up @@ -2268,13 +2228,10 @@ impl Array {
let len = o.length_of_array_like(context)?;

// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
let callback = match args.get(0).and_then(JsValue::as_object) {
Some(callback) if callback.is_callable() => callback,
_ => {
return context
.throw_type_error("Array.prototype.reduce: callback function is not callable")
}
};
let callback = args.get_or_undefined(0).as_callable().ok_or_else(|| {
context
.construct_type_error("Array.prototype.reduce: callback function is not callable")
})?;

// 4. If len = 0 and initialValue is not present, throw a TypeError exception.
if len == 0 && args.get(1).is_none() {
Expand Down Expand Up @@ -2366,14 +2323,11 @@ impl Array {
let len = o.length_of_array_like(context)?;

// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
let callback = match args.get(0).and_then(JsValue::as_object) {
Some(callback) if callback.is_callable() => callback,
_ => {
return context.throw_type_error(
"Array.prototype.reduceRight: callback function is not callable",
)
}
};
let callback = args.get_or_undefined(0).as_callable().ok_or_else(|| {
context.construct_type_error(
"Array.prototype.reduceRight: callback function is not callable",
)
})?;

// 4. If len is 0 and initialValue is not present, throw a TypeError exception.
if len == 0 && args.get(1).is_none() {
Expand Down
4 changes: 2 additions & 2 deletions boa/src/builtins/array_buffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,11 @@ impl ArrayBuffer {
let ctor = obj.species_constructor(StandardObjects::array_buffer_object, context)?;

// 16. Let new be ? Construct(ctor, « 𝔽(newLen) »).
let new = Self::constructor(&ctor.into(), &[new_len.into()], context)?;
let new = ctor.construct(&[new_len.into()], &ctor.clone().into(), context)?;

// 17. Perform ? RequireInternalSlot(new, [[ArrayBufferData]]).
let new_obj = if let Some(obj) = new.as_object() {
obj
obj.clone()
} else {
return context.throw_type_error("ArrayBuffer constructor returned non-object value");
};
Expand Down
23 changes: 10 additions & 13 deletions boa/src/builtins/bigint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,23 +123,20 @@ impl BigInt {
/// [spec]: https://tc39.es/ecma262/#sec-thisbigintvalue
#[inline]
fn this_bigint_value(value: &JsValue, context: &mut Context) -> JsResult<JsBigInt> {
match value {
value
// 1. If Type(value) is BigInt, return value.
JsValue::BigInt(ref bigint) => return Ok(bigint.clone()),

.as_bigint()
.cloned()
// 2. If Type(value) is Object and value has a [[BigIntData]] internal slot, then
// a. Assert: Type(value.[[BigIntData]]) is BigInt.
// b. Return value.[[BigIntData]].
JsValue::Object(ref object) => {
if let Some(bigint) = object.borrow().as_bigint() {
return Ok(bigint.clone());
}
}
_ => {}
}

// 3. Throw a TypeError exception.
Err(context.construct_type_error("'this' is not a BigInt"))
.or_else(|| {
value
.as_object()
.and_then(|obj| obj.borrow().as_bigint().cloned())
})
// 3. Throw a TypeError exception.
.ok_or_else(|| context.construct_type_error("'this' is not a BigInt"))
}

/// `BigInt.prototype.toString( [radix] )`
Expand Down
Loading

0 comments on commit 7a17da0

Please sign in to comment.