Browse Source

fix(boa): 15.4.4.19-8-c-ii-1.js (#1351)

* fix(boa): 15.4.4.19-8-c-ii-1.js

- skips undefined values on callback
- formats

Closes #1306

* add map callbackfn check whether callable

* major rewrite of map function for es compliance

* fix testcase 15.4.4.19-8-c-ii-1.js

* fmt

* add range error in array constructor

* fix clippy errors & fmt

* rebase
pull/1431/head
neeldug 4 years ago committed by GitHub
parent
commit
a4a76fe87c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 68
      boa/src/builtins/array/mod.rs
  2. 6
      boa/src/builtins/regexp/mod.rs
  3. 2
      boa/src/builtins/string/mod.rs
  4. 1
      test_ignore.txt

68
boa/src/builtins/array/mod.rs

@ -181,7 +181,7 @@ impl Array {
debug_assert!(number_of_args >= 2); debug_assert!(number_of_args >= 2);
// b. Let array be ? ArrayCreate(numberOfArgs, proto). // b. Let array be ? ArrayCreate(numberOfArgs, proto).
let array = Array::array_create(number_of_args as u64, Some(prototype), context)?; let array = Array::array_create(number_of_args, Some(prototype), context)?;
// c. Let k be 0. // c. Let k be 0.
// d. Repeat, while k < numberOfArgs, // d. Repeat, while k < numberOfArgs,
for (i, item) in args.iter().cloned().enumerate() { for (i, item) in args.iter().cloned().enumerate() {
@ -206,12 +206,12 @@ impl Array {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-arraycreate /// [spec]: https://tc39.es/ecma262/#sec-arraycreate
pub(crate) fn array_create( pub(crate) fn array_create(
length: u64, length: usize,
prototype: Option<GcObject>, prototype: Option<GcObject>,
context: &mut Context, context: &mut Context,
) -> Result<GcObject> { ) -> Result<GcObject> {
// 1. If length > 2^32 - 1, throw a RangeError exception. // 1. If length > 2^32 - 1, throw a RangeError exception.
if length > 2u64.pow(32) - 1 { if length > 2usize.pow(32) - 1 {
return Err(context.construct_range_error("array exceeded max size")); return Err(context.construct_range_error("array exceeded max size"));
} }
// 7. Return A. // 7. Return A.
@ -307,7 +307,7 @@ impl Array {
/// see: <https://tc39.es/ecma262/#sec-arrayspeciescreate> /// see: <https://tc39.es/ecma262/#sec-arrayspeciescreate>
pub(crate) fn array_species_create( pub(crate) fn array_species_create(
original_array: &GcObject, original_array: &GcObject,
length: u64, length: usize,
context: &mut Context, context: &mut Context,
) -> Result<GcObject> { ) -> Result<GcObject> {
// 1. Let isArray be ? IsArray(originalArray). // 1. Let isArray be ? IsArray(originalArray).
@ -428,7 +428,7 @@ impl Array {
.construct(&[len.into()], this, context)? .construct(&[len.into()], this, context)?
.as_object() .as_object()
.unwrap(), .unwrap(),
_ => Array::array_create(len as u64, None, context)?, _ => Array::array_create(len, None, context)?,
}; };
// 6. Let k be 0. // 6. Let k be 0.
@ -954,33 +954,41 @@ impl Array {
/// [spec]: https://tc39.es/ecma262/#sec-array.prototype.map /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.map
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
pub(crate) fn map(this: &Value, args: &[Value], context: &mut Context) -> Result<Value> { pub(crate) fn map(this: &Value, args: &[Value], context: &mut Context) -> Result<Value> {
if args.is_empty() { // 1. Let O be ? ToObject(this value).
return Err(Value::from(
"missing argument 0 when calling function Array.prototype.map",
));
}
let callback = args.get(0).cloned().unwrap_or_else(Value::undefined);
let this_val = args.get(1).cloned().unwrap_or_else(Value::undefined); let this_val = args.get(1).cloned().unwrap_or_else(Value::undefined);
let obj = this.to_object(context)?;
let length = this.get_field("length", context)?.to_length(context)?; // 2. Let len be ? LengthOfArrayLike(O).
let len = this.get_field("length", context)?.to_length(context)?;
if length > 2usize.pow(32) - 1 { // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
return context.throw_range_error("Invalid array length"); let callback = args.get(0).cloned().unwrap_or_else(Value::undefined);
if !callback.is_function() {
return context.throw_type_error("Callbackfn is not callable");
} }
// 4. Let A be ? ArraySpeciesCreate(O, len).
let new = Self::new_array(context); let arr = Self::array_species_create(&obj, len, context)?;
// 5. Let k be 0.
let values = (0..length) // 6. Repeat, while k < len,
.map(|idx| { for k in 0..len {
let element = this.get_field(idx, context)?; // a. Let Pk be ! ToString(𝔽(k)).
let args = [element, Value::from(idx), new.clone()]; // b. Let k_present be ? HasProperty(O, Pk).
let k_present = this.has_field(k);
context.call(&callback, &this_val, &args) // c. If k_present is true, then
}) if k_present {
.collect::<Result<Vec<Value>>>()?; // i. Let kValue be ? Get(O, Pk).
let k_value = this.get_field(k, context)?;
Self::construct_array(&new, &values, context) let args = [k_value, Value::from(k), this.into()];
// ii. Let mappedValue be ? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »).
let value = context.call(&callback, &this_val, &args)?;
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
arr.ordinary_define_own_property(
k.into(),
DataDescriptor::new(value, Attribute::all()).into(),
);
}
// d. Set k to k + 1.
}
// 7. Return A.
Ok(Value::from(arr))
} }
/// `Array.prototype.indexOf( searchElement[, fromIndex ] )` /// `Array.prototype.indexOf( searchElement[, fromIndex ] )`

6
boa/src/builtins/regexp/mod.rs

@ -820,9 +820,9 @@ impl RegExp {
} }
// 16. Let n be the number of elements in r's captures List. (This is the same value as 22.2.2.1's NcapturingParens.) // 16. Let n be the number of elements in r's captures List. (This is the same value as 22.2.2.1's NcapturingParens.)
let n = match_value.captures.len() as u64; let n = match_value.captures.len();
// 17. Assert: n < 23^2 - 1. // 17. Assert: n < 23^2 - 1.
assert!(n < 23u64.pow(2) - 1); debug_assert!(n < 23usize.pow(2) - 1);
// 18. Let A be ! ArrayCreate(n + 1). // 18. Let A be ! ArrayCreate(n + 1).
// 19. Assert: The mathematical value of A's "length" property is n + 1. // 19. Assert: The mathematical value of A's "length" property is n + 1.
@ -861,7 +861,7 @@ impl RegExp {
// 27. For each integer i such that i ≥ 1 and i ≤ n, in ascending order, do // 27. For each integer i such that i ≥ 1 and i ≤ n, in ascending order, do
for i in 1..=n { for i in 1..=n {
// a. Let captureI be ith element of r's captures List. // a. Let captureI be ith element of r's captures List.
let capture = match_value.group(i as usize); let capture = match_value.group(i);
let captured_value = match capture { let captured_value = match capture {
// b. If captureI is undefined, let capturedValue be undefined. // b. If captureI is undefined, let capturedValue be undefined.

2
boa/src/builtins/string/mod.rs

@ -1189,7 +1189,7 @@ impl String {
let this_str = this.to_string(context)?; let this_str = this.to_string(context)?;
// 4. Let A be ! ArrayCreate(0). // 4. Let A be ! ArrayCreate(0).
let a = Array::array_create(0, None, context).unwrap(); let a = Array::array_create(0, None, context)?;
// 5. Let lengthA be 0. // 5. Let lengthA be 0.
let mut length_a = 0; let mut length_a = 0;

1
test_ignore.txt

@ -11,7 +11,6 @@ feature:json-modules
// These seem to run forever: // These seem to run forever:
arg-length-exceeding-integer-limit arg-length-exceeding-integer-limit
15.4.4.19-8-c-ii-1
// These generate a stack overflow // These generate a stack overflow
tco-call tco-call

Loading…
Cancel
Save