From 476082904007c1d5aa15aeb550815495721a520d Mon Sep 17 00:00:00 2001 From: "Iban Eguia (Razican)" Date: Sat, 22 May 2021 11:51:08 +0200 Subject: [PATCH] Fix Array.prototype.filter Co-authored-by: tofpie --- Cargo.lock | 84 ++++++++++++++------------ boa/src/builtins/array/mod.rs | 107 +++++++++++++++++++++++++++------- boa/src/builtins/json/mod.rs | 3 +- boa/src/builtins/map/mod.rs | 3 +- boa/src/builtins/math/mod.rs | 14 ++--- 5 files changed, 143 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6103bf72c5d..7673f60f1c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -152,9 +152,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cast" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc38c385bfd7e444464011bb24820f40dd1c76bcdfa1b78611cb7c2e5cafab75" +checksum = "57cdfa5d50aad6cb4d44dcab6101a7f79925bd59d82ca42f38a9856a28865374" dependencies = [ "rustc_version", ] @@ -209,7 +209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4ea1881992efc993e4dc50a324cdbd03216e41bdc8385720ff47efc9bd2ca8" dependencies = [ "error-code", - "str-buf 1.0.5", + "str-buf", "winapi", ] @@ -368,12 +368,12 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" [[package]] name = "error-code" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d4871041f3339e2cd4a23c698f89519e1ca62aa73190eddcc18dde4ee11e8ff" +checksum = "b5115567ac25674e0043e472be13d14e537f37ea8aa4bdc4aef0c89add1db1ff" dependencies = [ "libc", - "str-buf 2.0.0", + "str-buf", ] [[package]] @@ -597,9 +597,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" +checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" dependencies = [ "wasm-bindgen", ] @@ -688,9 +688,9 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "measureme" -version = "9.1.1" +version = "9.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cf14eb7d2eea897d9949b68f19e165638755e3a1a3c0941b6b6c3e00141f2c" +checksum = "78f7a41bc6f856a2cf0e95094ad5121f82500e2d9a0f3c0171d98f6566d8117d" dependencies = [ "log", "memmap2", @@ -816,9 +816,9 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "openssl-probe" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "openssl-sys" @@ -873,6 +873,15 @@ dependencies = [ "libc", ] +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + [[package]] name = "pkg-config" version = "0.3.19" @@ -881,9 +890,9 @@ checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" [[package]] name = "plotters" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ca0ae5f169d0917a7c7f5a9c1a3d3d9598f18f529dd2b8373ed988efea307a" +checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" dependencies = [ "num-traits", "plotters-backend", @@ -939,9 +948,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" dependencies = [ "unicode-xid", ] @@ -1007,9 +1016,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" dependencies = [ "autocfg", "crossbeam-deque", @@ -1019,9 +1028,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -1093,9 +1102,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" -version = "0.2.3" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" dependencies = [ "semver", ] @@ -1163,18 +1172,21 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ "semver-parser", ] [[package]] name = "semver-parser" -version = "0.7.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] [[package]] name = "serde" @@ -1241,12 +1253,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" -[[package]] -name = "str-buf" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66ae6a6cd930c97707cb3f1b62aadb8ddddd2fefa9df539564b3bfaa15dd31f" - [[package]] name = "strsim" version = "0.8.0" @@ -1345,6 +1351,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicode-bidi" version = "0.3.5" @@ -1407,9 +1419,9 @@ checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" [[package]] name = "vcpkg" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdbff6266a24120518560b5dc983096efb98462e51d0d68169895b237be3e5d" +checksum = "025ce40a007e1907e58d5bc1a594def78e5573bb0b1160bc389634e8f12e4faa" [[package]] name = "vec_map" @@ -1496,9 +1508,9 @@ checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" [[package]] name = "web-sys" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" +checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 587be1561ca..d60f056f3c9 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -262,6 +262,51 @@ impl Array { Ok(array_obj_ptr) } + /// Utility function used to specify the creation of a new Array object using a constructor + /// function that is derived from original_array. + /// + /// see: + pub(crate) fn array_species_create( + original_array: &GcObject, + length: u32, + context: &mut Context, + ) -> Result { + if !original_array.is_array() { + return Ok(Self::array_create(length, None, context)); + } + let c = original_array.get( + &"constructor".into(), + original_array.clone().into(), + context, + )?; + // Step 4 is ignored, as there are no different realms for now + let c = if let Some(c) = c.as_object() { + let c = c.get( + &WellKnownSymbols::species().into(), + c.clone().into(), + context, + )?; + if c.is_null_or_undefined() { + Value::undefined() + } else { + c + } + } else { + c + }; + if c.is_undefined() { + return Ok(Self::array_create(length, None, context)); + } + if let Some(c) = c.as_object() { + if !c.is_constructable() { + return context.throw_type_error("Symbol.species must be a constructor"); + } + c.construct(&[Value::from(length)], c.clone().into(), context) + } else { + context.throw_type_error("Symbol.species must be a constructor") + } + } + /// Utility function which takes an existing array object and puts additional /// values on the end, correctly rewriting the length pub(crate) fn add_to_array_object( @@ -1211,37 +1256,57 @@ impl Array { /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.filter /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter pub(crate) fn filter(this: &Value, args: &[Value], context: &mut Context) -> Result { - if args.is_empty() { - return Err(Value::from( - "missing argument 0 when calling function Array.prototype.filter", - )); - } - - let callback = args.get(0).cloned().unwrap_or_else(Value::undefined); + let o = this.to_object(context)?; + let length = o + .get(&"length".into(), Value::from(o.clone()), context)? + .to_length(context)?; + + 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 this_val = args.get(1).cloned().unwrap_or_else(Value::undefined); - let length = this.get_field("length", context)?.to_length(context)?; + if !callback.is_callable() { + return context.throw_type_error("the callback must be callable"); + } - let new = Self::new_array(context); + let mut a = Self::array_species_create(&o, 0, context)? + .as_object() + .expect("array_species_create must create an object"); - let values = (0..length) - .map(|idx| { - let element = this.get_field(idx, context)?; + let mut to = 0u32; + for idx in 0..length { + if o.has_property(&idx.into()) { + let element = o.get(&idx.into(), Value::from(o.clone()), context)?; - let args = [element.clone(), Value::from(idx), new.clone()]; + let args = [element.clone(), Value::from(idx), Value::from(o.clone())]; - let callback_result = context.call(&callback, &this_val, &args)?; + let callback_result = callback.call(&this_val, &args, context)?; if callback_result.to_boolean() { - Ok(Some(element)) - } else { - Ok(None) + if !a.define_own_property( + to, + DataDescriptor::new( + element, + Attribute::WRITABLE | Attribute::ENUMERABLE | Attribute::CONFIGURABLE, + ) + .into(), + context, + )? { + return context.throw_type_error("cannot set property in array"); + } + to += 1; } - }) - .collect::>>>()?; - let values = values.into_iter().flatten().collect::>(); + } + } - Self::construct_array(&new, &values, context) + Ok(a.into()) } /// Array.prototype.some ( callbackfn [ , thisArg ] ) diff --git a/boa/src/builtins/json/mod.rs b/boa/src/builtins/json/mod.rs index 42c21adad43..fbb46bde1fe 100644 --- a/boa/src/builtins/json/mod.rs +++ b/boa/src/builtins/json/mod.rs @@ -42,13 +42,12 @@ impl BuiltIn for Json { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let to_string_tag = WellKnownSymbols::to_string_tag(); - let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; let json_object = ObjectInitializer::new(context) - .property(to_string_tag, "JSON", attribute) .function(Self::parse, "parse", 2) .function(Self::stringify, "stringify", 3) + .property(to_string_tag, Json::NAME, attribute) .build(); (Self::NAME, json_object.into(), Self::attribute()) diff --git a/boa/src/builtins/map/mod.rs b/boa/src/builtins/map/mod.rs index 5c0e606558a..711579574d6 100644 --- a/boa/src/builtins/map/mod.rs +++ b/boa/src/builtins/map/mod.rs @@ -42,7 +42,6 @@ impl BuiltIn for Map { let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let to_string_tag = WellKnownSymbols::to_string_tag(); - let iterator_symbol = WellKnownSymbols::iterator(); let entries_function = FunctionBuilder::new(context, Self::entries) @@ -66,7 +65,7 @@ impl BuiltIn for Map { ) .property( to_string_tag, - "Map", + Self::NAME, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( diff --git a/boa/src/builtins/math/mod.rs b/boa/src/builtins/math/mod.rs index 130eb63f563..284319e2a0a 100644 --- a/boa/src/builtins/math/mod.rs +++ b/boa/src/builtins/math/mod.rs @@ -31,12 +31,12 @@ impl BuiltIn for Math { } fn init(context: &mut Context) -> (&'static str, Value, Attribute) { - let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); use std::f64; - let to_string_tag = WellKnownSymbols::to_string_tag(); + let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; + let string_tag = WellKnownSymbols::to_string_tag(); let object = ObjectInitializer::new(context) .property("E", f64::consts::E, attribute) .property("LN2", f64::consts::LN_2, attribute) @@ -46,11 +46,6 @@ impl BuiltIn for Math { .property("SQRT1_2", 0.5_f64.sqrt(), attribute) .property("SQRT2", f64::consts::SQRT_2, attribute) .property("PI", f64::consts::PI, attribute) - .property( - to_string_tag, - "Math", - Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, - ) .function(Self::abs, "abs", 1) .function(Self::acos, "acos", 1) .function(Self::acosh, "acosh", 1) @@ -86,6 +81,11 @@ impl BuiltIn for Math { .function(Self::tan, "tan", 1) .function(Self::tanh, "tanh", 1) .function(Self::trunc, "trunc", 1) + .property( + string_tag, + Math::NAME, + Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, + ) .build(); (Self::NAME, object.into(), Self::attribute())