From 7984a92cb6f7995dfd5b0dc73c35883129c2bf0a Mon Sep 17 00:00:00 2001 From: jedel1043 Date: Sat, 21 Aug 2021 22:59:40 -0500 Subject: [PATCH] Replace calls to `get/unwrap_or` with `get_or_undefined` --- boa/src/builtins/array/mod.rs | 30 +++++------ boa/src/builtins/bigint/mod.rs | 16 +++--- boa/src/builtins/console/mod.rs | 7 ++- boa/src/builtins/date/mod.rs | 4 +- boa/src/builtins/function/mod.rs | 8 +-- boa/src/builtins/json/mod.rs | 6 ++- boa/src/builtins/map/mod.rs | 17 +++---- boa/src/builtins/mod.rs | 2 +- boa/src/builtins/number/mod.rs | 10 ++-- boa/src/builtins/object/mod.rs | 32 +++++------- boa/src/builtins/reflect/mod.rs | 31 +++++------- boa/src/builtins/regexp/mod.rs | 14 +++--- boa/src/builtins/set/mod.rs | 12 +++-- boa/src/builtins/string/mod.rs | 85 ++++++++++++++------------------ boa/src/builtins/symbol/mod.rs | 4 +- boa/src/class.rs | 3 +- 16 files changed, 135 insertions(+), 146 deletions(-) diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 1bcc9223542..f9bead84e45 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -25,6 +25,8 @@ use crate::{ }; use std::cmp::{max, min, Ordering}; +use super::JsArgs; + /// JavaScript `Array` built-in implementation. #[derive(Debug, Clone, Copy)] pub(crate) struct Array; @@ -687,7 +689,7 @@ impl Array { // i. Let kValue be ? Get(O, Pk). let k_value = o.get(pk, context)?; // ii. Perform ? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »). - let this_arg = args.get(1).cloned().unwrap_or_else(JsValue::undefined); + let this_arg = args.get_or_undefined(1); callback.call(&this_arg, &[k_value, k.into(), o.clone().into()], context)?; } // d. Set k to k + 1. @@ -1022,7 +1024,7 @@ impl Array { return context.throw_type_error("Array.prototype.every: callback is not callable"); }; - let this_arg = args.get(1).cloned().unwrap_or_default(); + let this_arg = args.get_or_undefined(1); // 4. Let k be 0. // 5. Repeat, while k < len, @@ -1070,7 +1072,7 @@ 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(0).cloned().unwrap_or_default(); + let callback = args.get_or_undefined(0); if !callback.is_function() { return context.throw_type_error("Array.prototype.map: Callbackfn is not callable"); } @@ -1078,7 +1080,7 @@ impl Array { // 4. Let A be ? ArraySpeciesCreate(O, len). let a = Self::array_species_create(&o, len, context)?; - let this_arg = args.get(1).cloned().unwrap_or_default(); + let this_arg = args.get_or_undefined(1); // 5. Let k be 0. // 6. Repeat, while k < len, @@ -1156,7 +1158,7 @@ impl Array { } }; - let search_element = args.get(0).cloned().unwrap_or_default(); + let search_element = args.get_or_undefined(0); // 10. Repeat, while k < len, while k < len { @@ -1232,7 +1234,7 @@ impl Array { IntegerOrInfinity::Integer(n) => len + n, }; - let search_element = args.get(0).cloned().unwrap_or_default(); + let search_element = args.get_or_undefined(0); // 8. Repeat, while k ≥ 0, while k >= 0 { @@ -1286,7 +1288,7 @@ impl Array { } }; - let this_arg = args.get(1).cloned().unwrap_or_default(); + let this_arg = args.get_or_undefined(1); // 4. Let k be 0. let mut k = 0; @@ -1347,7 +1349,7 @@ impl Array { } }; - let this_arg = args.get(1).cloned().unwrap_or_default(); + let this_arg = args.get_or_undefined(1); // 4. Let k be 0. let mut k = 0; @@ -1451,7 +1453,7 @@ 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(0).cloned().unwrap_or_default(); + let mapper_function = args.get_or_undefined(0); if !mapper_function.is_function() { return context.throw_type_error("flatMap mapper function is not callable"); } @@ -1467,7 +1469,7 @@ impl Array { 0, 1, Some(mapper_function.as_object().unwrap()), - &args.get(1).cloned().unwrap_or_default(), + &args.get_or_undefined(1), context, )?; @@ -1622,7 +1624,7 @@ impl Array { // 10. Else, let final be min(relativeEnd, len). let final_ = Self::get_relative_end(context, args.get(2), len)?; - let value = args.get(0).cloned().unwrap_or_default(); + let value = args.get_or_undefined(0); // 11. Repeat, while k < final, while k < final_ { @@ -1693,7 +1695,7 @@ impl Array { } } - let search_element = args.get(0).cloned().unwrap_or_default(); + let search_element = args.get_or_undefined(0); // 10. Repeat, while k < len, while k < len { @@ -1813,7 +1815,7 @@ impl Array { "missing argument 0 when calling function Array.prototype.filter", ) })?; - let this_val = args.get(1).cloned().unwrap_or_else(JsValue::undefined); + let this_val = args.get_or_undefined(1); if !callback.is_callable() { return context.throw_type_error("the callback must be callable"); @@ -1899,7 +1901,7 @@ impl Array { // i. Let kValue be ? Get(O, Pk). let k_value = o.get(k, context)?; // ii. Let testResult be ! ToBoolean(? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »)). - let this_arg = args.get(1).cloned().unwrap_or_default(); + let this_arg = args.get_or_undefined(1); let test_result = callback .call(&this_arg, &[k_value, k.into(), o.clone().into()], context)? .to_boolean(); diff --git a/boa/src/builtins/bigint/mod.rs b/boa/src/builtins/bigint/mod.rs index 1e9a1553fff..499650f9e2a 100644 --- a/boa/src/builtins/bigint/mod.rs +++ b/boa/src/builtins/bigint/mod.rs @@ -13,8 +13,12 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt use crate::{ - builtins::BuiltIn, object::ConstructorBuilder, property::Attribute, symbol::WellKnownSymbols, - value::IntegerOrInfinity, BoaProfiler, Context, JsBigInt, JsResult, JsValue, + builtins::{BuiltIn, JsArgs}, + object::ConstructorBuilder, + property::Attribute, + symbol::WellKnownSymbols, + value::IntegerOrInfinity, + BoaProfiler, Context, JsBigInt, JsResult, JsValue, }; #[cfg(test)] mod tests; @@ -131,7 +135,7 @@ impl BigInt { // 1. Let x be ? thisBigIntValue(this value). let x = Self::this_bigint_value(this, context)?; - let radix = args.get(0).cloned().unwrap_or_default(); + let radix = args.get_or_undefined(0); // 2. If radix is undefined, let radixMV be 10. let radix_mv = if radix.is_undefined() { @@ -234,10 +238,8 @@ impl BigInt { fn calculate_as_uint_n(args: &[JsValue], context: &mut Context) -> JsResult<(JsBigInt, u32)> { use std::convert::TryFrom; - let undefined_value = JsValue::undefined(); - - let bits_arg = args.get(0).unwrap_or(&undefined_value); - let bigint_arg = args.get(1).unwrap_or(&undefined_value); + let bits_arg = args.get_or_undefined(0); + let bigint_arg = args.get_or_undefined(1); let bits = bits_arg.to_index(context)?; let bits = u32::try_from(bits).unwrap_or(u32::MAX); diff --git a/boa/src/builtins/console/mod.rs b/boa/src/builtins/console/mod.rs index 95b2561738f..b645b5739b7 100644 --- a/boa/src/builtins/console/mod.rs +++ b/boa/src/builtins/console/mod.rs @@ -17,7 +17,7 @@ mod tests; use crate::{ - builtins::BuiltIn, + builtins::{BuiltIn, JsArgs}, object::ObjectInitializer, property::Attribute, value::{display::display_obj, JsValue}, @@ -90,7 +90,7 @@ pub fn formatter(data: &[JsValue], context: &mut Context) -> JsResult { } /* object, FIXME: how to render this properly? */ 'o' | 'O' => { - let arg = data.get(arg_index).cloned().unwrap_or_default(); + let arg = data.get_or_undefined(arg_index); formatted.push_str(&format!("{}", arg.display())); arg_index += 1 } @@ -564,9 +564,8 @@ impl Console { /// [spec]: https://console.spec.whatwg.org/#dir /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/console/dir pub(crate) fn dir(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { - let undefined = JsValue::undefined(); logger( - LogMessage::Info(display_obj(args.get(0).unwrap_or(&undefined), true)), + LogMessage::Info(display_obj(&args.get_or_undefined(0), true)), context.console(), ); diff --git a/boa/src/builtins/date/mod.rs b/boa/src/builtins/date/mod.rs index fb056511e8e..a3be0770e6b 100644 --- a/boa/src/builtins/date/mod.rs +++ b/boa/src/builtins/date/mod.rs @@ -13,6 +13,8 @@ use crate::{ use chrono::{prelude::*, Duration, LocalResult}; use std::fmt::Display; +use super::JsArgs; + /// The number of nanoseconds in a millisecond. const NANOS_PER_MS: i64 = 1_000_000; /// The number of milliseconds in an hour. @@ -523,7 +525,7 @@ impl Date { return context.throw_type_error("Date.prototype[@@toPrimitive] called on non object"); }; - let hint = args.get(0).cloned().unwrap_or_default(); + let hint = args.get_or_undefined(0); let try_first = match hint.as_string().map(|s| s.as_str()) { // 3. If hint is "string" or "default", then diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index fe9869dc2f6..60d82532cab 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -26,6 +26,8 @@ use bitflags::bitflags; use std::fmt::{self, Debug}; use std::rc::Rc; +use super::JsArgs; + #[cfg(test)] mod tests; @@ -322,7 +324,7 @@ impl BuiltInFunctionObject { if !this.is_function() { return context.throw_type_error(format!("{} is not a function", this.display())); } - let this_arg: JsValue = args.get(0).cloned().unwrap_or_default(); + let this_arg = args.get_or_undefined(0); // TODO?: 3. Perform PrepareForTailCall let start = if !args.is_empty() { 1 } else { 0 }; context.call(this, &this_arg, &args[start..]) @@ -343,8 +345,8 @@ impl BuiltInFunctionObject { if !this.is_function() { return context.throw_type_error(format!("{} is not a function", this.display())); } - let this_arg = args.get(0).cloned().unwrap_or_default(); - let arg_array = args.get(1).cloned().unwrap_or_default(); + let this_arg = args.get_or_undefined(0); + let arg_array = args.get_or_undefined(1); if arg_array.is_null_or_undefined() { // TODO?: 3.a. PrepareForTailCall return context.call(this, &this_arg, &[]); diff --git a/boa/src/builtins/json/mod.rs b/boa/src/builtins/json/mod.rs index f738292bcd7..9473a503ad1 100644 --- a/boa/src/builtins/json/mod.rs +++ b/boa/src/builtins/json/mod.rs @@ -28,6 +28,8 @@ use crate::{ }; use serde_json::{self, Value as JSONValue}; +use super::JsArgs; + #[cfg(test)] mod tests; @@ -158,7 +160,7 @@ impl Json { let mut property_list = None; let mut replacer_function = None; - let replacer = args.get(1).cloned().unwrap_or_default(); + let replacer = args.get_or_undefined(1); // 4. If Type(replacer) is Object, then if let Some(replacer_obj) = replacer.as_object() { @@ -214,7 +216,7 @@ impl Json { } } - let mut space = args.get(2).cloned().unwrap_or_default(); + let mut space = args.get_or_undefined(2); // 5. If Type(space) is Object, then if let Some(space_obj) = space.as_object() { diff --git a/boa/src/builtins/map/mod.rs b/boa/src/builtins/map/mod.rs index 2572de182d6..dee84aa70b4 100644 --- a/boa/src/builtins/map/mod.rs +++ b/boa/src/builtins/map/mod.rs @@ -26,6 +26,8 @@ use map_iterator::MapIterator; use self::ordered_map::MapLock; +use super::JsArgs; + pub mod ordered_map; #[cfg(test)] mod tests; @@ -245,11 +247,8 @@ impl Map { args: &[JsValue], context: &mut Context, ) -> JsResult { - let (key, value) = match args.len() { - 0 => (JsValue::undefined(), JsValue::undefined()), - 1 => (args[0].clone(), JsValue::undefined()), - _ => (args[0].clone(), args[1].clone()), - }; + let key = args.get_or_undefined(0); + let value = args.get_or_undefined(1); let size = if let Some(object) = this.as_object() { if let Some(map) = object.borrow_mut().as_map_mut() { @@ -281,7 +280,7 @@ impl Map { args: &[JsValue], context: &mut Context, ) -> JsResult { - let key = args.get(0).cloned().unwrap_or_default(); + let key = args.get_or_undefined(0); let (deleted, size) = if let Some(object) = this.as_object() { if let Some(map) = object.borrow_mut().as_map_mut() { @@ -312,7 +311,7 @@ impl Map { args: &[JsValue], context: &mut Context, ) -> JsResult { - let key = args.get(0).cloned().unwrap_or_default(); + let key = args.get_or_undefined(0); if let JsValue::Object(ref object) = this { let object = object.borrow(); @@ -361,7 +360,7 @@ impl Map { args: &[JsValue], context: &mut Context, ) -> JsResult { - let key = args.get(0).cloned().unwrap_or_default(); + let key = args.get_or_undefined(0); if let JsValue::Object(ref object) = this { let object = object.borrow(); @@ -393,7 +392,7 @@ impl Map { } let callback_arg = &args[0]; - let this_arg = args.get(1).cloned().unwrap_or_else(JsValue::undefined); + let this_arg = args.get_or_undefined(1); let mut index = 0; diff --git a/boa/src/builtins/mod.rs b/boa/src/builtins/mod.rs index 4f8819ebee9..4b2124e196f 100644 --- a/boa/src/builtins/mod.rs +++ b/boa/src/builtins/mod.rs @@ -113,7 +113,7 @@ pub fn init(context: &mut Context) { } } -pub(crate) trait JsArgs { +pub trait JsArgs { fn get_or_undefined(&self, index: usize) -> JsValue; } diff --git a/boa/src/builtins/number/mod.rs b/boa/src/builtins/number/mod.rs index 5349865cd07..f44290ab2e1 100644 --- a/boa/src/builtins/number/mod.rs +++ b/boa/src/builtins/number/mod.rs @@ -13,8 +13,8 @@ //! [spec]: https://tc39.es/ecma262/#sec-number-object //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number -use super::function::make_builtin_fn; use super::string::is_trimmable_whitespace; +use super::{function::make_builtin_fn, JsArgs}; use crate::{ builtins::BuiltIn, object::{ConstructorBuilder, ObjectData, PROTOTYPE}, @@ -392,12 +392,12 @@ impl Number { args: &[JsValue], context: &mut Context, ) -> JsResult { - let precision = args.get(0).cloned().unwrap_or_default(); + let precision = args.get_or_undefined(0); // 1 & 6 let mut this_num = Self::this_number_value(this, context)?; // 2 - if precision == JsValue::undefined() { + if precision.is_undefined() { return Self::to_string(this, &[], context); } @@ -720,7 +720,7 @@ impl Number { args: &[JsValue], context: &mut Context, ) -> JsResult { - if let (Some(val), radix) = (args.get(0), args.get(1)) { + if let (Some(val), radix) = (args.get(0), args.get_or_undefined(1)) { // 1. Let inputString be ? ToString(string). let input_string = val.to_string(context)?; @@ -745,7 +745,7 @@ impl Number { } // 6. Let R be ℝ(? ToInt32(radix)). - let mut var_r = radix.cloned().unwrap_or_default().to_i32(context)?; + let mut var_r = radix.to_i32(context)?; // 7. Let stripPrefix be true. let mut strip_prefix = true; diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 4f261c70b14..4f0d2892224 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -14,7 +14,7 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object use crate::{ - builtins::BuiltIn, + builtins::{BuiltIn, JsArgs}, object::{ ConstructorBuilder, JsObject, Object as BuiltinObject, ObjectData, ObjectInitializer, ObjectKind, PROTOTYPE, @@ -129,8 +129,8 @@ impl Object { /// [spec]: https://tc39.es/ecma262/#sec-object.create /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create pub fn create(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { - let prototype = args.get(0).cloned().unwrap_or_else(JsValue::undefined); - let properties = args.get(1).cloned().unwrap_or_else(JsValue::undefined); + let prototype = args.get_or_undefined(0); + let properties = args.get_or_undefined(1); let obj = match prototype { JsValue::Object(_) | JsValue::Null => JsObject::new(BuiltinObject::with_prototype( @@ -168,10 +168,7 @@ impl Object { args: &[JsValue], context: &mut Context, ) -> JsResult { - let object = args - .get(0) - .unwrap_or(&JsValue::undefined()) - .to_object(context)?; + let object = args.get_or_undefined(0).to_object(context)?; if let Some(key) = args.get(1) { let key = key.to_property_key(context)?; @@ -270,8 +267,8 @@ impl Object { /// Uses the SameValue algorithm to check equality of objects pub fn is(_: &JsValue, args: &[JsValue], _: &mut Context) -> JsResult { - let x = args.get(0).cloned().unwrap_or_else(JsValue::undefined); - let y = args.get(1).cloned().unwrap_or_else(JsValue::undefined); + let x = args.get_or_undefined(0); + let y = args.get_or_undefined(1); Ok(JsValue::same_value(&x, &y).into()) } @@ -313,7 +310,7 @@ impl Object { .clone(); // 2. If Type(proto) is neither Object nor Null, throw a TypeError exception. - let proto = args.get(1).cloned().unwrap_or_default(); + let proto = args.get_or_undefined(1); if !matches!(proto.get_type(), Type::Object | Type::Null) { return ctx.throw_type_error(format!( "expected an object or null, got {}", @@ -356,8 +353,7 @@ impl Object { args: &[JsValue], context: &mut Context, ) -> JsResult { - let undefined = JsValue::undefined(); - let mut v = args.get(0).unwrap_or(&undefined).clone(); + let mut v = args.get_or_undefined(0); if !v.is_object() { return Ok(JsValue::new(false)); } @@ -379,7 +375,7 @@ impl Object { args: &[JsValue], context: &mut Context, ) -> JsResult { - let object = args.get(0).cloned().unwrap_or_else(JsValue::undefined); + let object = args.get_or_undefined(0); if let Some(object) = object.as_object() { let key = args .get(1) @@ -413,10 +409,10 @@ impl Object { args: &[JsValue], context: &mut Context, ) -> JsResult { - let arg = args.get(0).cloned().unwrap_or_default(); + let arg = args.get_or_undefined(0); let arg_obj = arg.as_object(); if let Some(obj) = arg_obj { - let props = args.get(1).cloned().unwrap_or_else(JsValue::undefined); + let props = args.get_or_undefined(1); object_define_properties(&obj, props, context)?; Ok(arg) } else { @@ -566,11 +562,7 @@ impl Object { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign pub fn assign(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { // 1. Let to be ? ToObject(target). - let to = args - .get(0) - .cloned() - .unwrap_or_default() - .to_object(context)?; + let to = args.get_or_undefined(0).to_object(context)?; // 2. If only one argument was passed, return to. if args.len() == 1 { diff --git a/boa/src/builtins/reflect/mod.rs b/boa/src/builtins/reflect/mod.rs index 77481072493..7944ac60418 100644 --- a/boa/src/builtins/reflect/mod.rs +++ b/boa/src/builtins/reflect/mod.rs @@ -18,7 +18,7 @@ use crate::{ BoaProfiler, Context, JsResult, JsValue, }; -use super::Array; +use super::{Array, JsArgs}; #[cfg(test)] mod tests; @@ -81,8 +81,8 @@ impl Reflect { .get(0) .and_then(|v| v.as_object()) .ok_or_else(|| context.construct_type_error("target must be a function"))?; - let this_arg = args.get(1).cloned().unwrap_or_default(); - let args_list = args.get(2).cloned().unwrap_or_default(); + let this_arg = args.get_or_undefined(1); + let args_list = args.get_or_undefined(2); if !target.is_callable() { return context.throw_type_error("target must be a function"); @@ -108,7 +108,7 @@ impl Reflect { .get(0) .and_then(|v| v.as_object()) .ok_or_else(|| context.construct_type_error("target must be a function"))?; - let args_list = args.get(1).cloned().unwrap_or_default(); + let args_list = args.get_or_undefined(1); if !target.is_constructable() { return context.throw_type_error("target must be a constructor"); @@ -140,12 +140,11 @@ impl Reflect { args: &[JsValue], context: &mut Context, ) -> JsResult { - let undefined = JsValue::undefined(); let target = args .get(0) .and_then(|v| v.as_object()) .ok_or_else(|| context.construct_type_error("target must be an object"))?; - let key = args.get(1).unwrap_or(&undefined).to_property_key(context)?; + let key = args.get_or_undefined(1).to_property_key(context)?; let prop_desc: JsValue = args .get(2) .and_then(|v| v.as_object()) @@ -170,12 +169,11 @@ impl Reflect { args: &[JsValue], context: &mut Context, ) -> JsResult { - let undefined = JsValue::undefined(); let target = args .get(0) .and_then(|v| v.as_object()) .ok_or_else(|| context.construct_type_error("target must be an object"))?; - let key = args.get(1).unwrap_or(&undefined).to_property_key(context)?; + let key = args.get_or_undefined(1).to_property_key(context)?; Ok(target.__delete__(&key, context)?.into()) } @@ -189,14 +187,13 @@ impl Reflect { /// [spec]: https://tc39.es/ecma262/#sec-reflect.get /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/get pub(crate) fn get(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { - let undefined = JsValue::undefined(); // 1. If Type(target) is not Object, throw a TypeError exception. let target = args .get(0) .and_then(|v| v.as_object()) .ok_or_else(|| context.construct_type_error("target must be an object"))?; // 2. Let key be ? ToPropertyKey(propertyKey). - let key = args.get(1).unwrap_or(&undefined).to_property_key(context)?; + let key = args.get_or_undefined(1).to_property_key(context)?; // 3. If receiver is not present, then let receiver = if let Some(receiver) = args.get(2).cloned() { receiver @@ -347,21 +344,18 @@ impl Reflect { /// [spec]: https://tc39.es/ecma262/#sec-reflect.set /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/set pub(crate) fn set(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { - let undefined = JsValue::undefined(); let target = args .get(0) .and_then(|v| v.as_object()) .ok_or_else(|| context.construct_type_error("target must be an object"))?; - let key = args.get(1).unwrap_or(&undefined).to_property_key(context)?; - let value = args.get(2).unwrap_or(&undefined); + let key = args.get_or_undefined(1).to_property_key(context)?; + let value = args.get_or_undefined(2); let receiver = if let Some(receiver) = args.get(3).cloned() { receiver } else { target.clone().into() }; - Ok(target - .__set__(key, value.clone(), receiver, context)? - .into()) + Ok(target.__set__(key, value, receiver, context)?.into()) } /// Sets the prototype of an object. @@ -377,15 +371,14 @@ impl Reflect { args: &[JsValue], context: &mut Context, ) -> JsResult { - let undefined = JsValue::undefined(); let mut target = args .get(0) .and_then(|v| v.as_object()) .ok_or_else(|| context.construct_type_error("target must be an object"))?; - let proto = args.get(1).unwrap_or(&undefined); + let proto = args.get_or_undefined(1); if !proto.is_null() && !proto.is_object() { return context.throw_type_error("proto must be an object or null"); } - Ok(target.__set_prototype_of__(proto.clone(), context)?.into()) + Ok(target.__set_prototype_of__(proto, context)?.into()) } } diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index b51a9683fa3..99ff6232c80 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -23,6 +23,8 @@ use crate::{ use regexp_string_iterator::RegExpStringIterator; use regress::Regex; +use super::JsArgs; + #[cfg(test)] mod tests; @@ -187,8 +189,8 @@ impl RegExp { args: &[JsValue], context: &mut Context, ) -> JsResult { - let pattern = args.get(0).cloned().unwrap_or_else(JsValue::undefined); - let flags = args.get(1).cloned().unwrap_or_else(JsValue::undefined); + let pattern = args.get_or_undefined(0); + let flags = args.get_or_undefined(1); // 1. Let patternIsRegExp be ? IsRegExp(pattern). let pattern_is_regexp = if let JsValue::Object(obj) = &pattern { @@ -275,8 +277,8 @@ impl RegExp { /// /// [spec]: https://tc39.es/ecma262/#sec-regexpinitialize fn initialize(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { - let pattern = args.get(0).cloned().unwrap_or_else(JsValue::undefined); - let flags = args.get(1).cloned().unwrap_or_else(JsValue::undefined); + let pattern = args.get_or_undefined(0); + let flags = args.get_or_undefined(1); // 1. If pattern is undefined, let P be the empty String. // 2. Else, let P be ? ToString(pattern). @@ -1282,7 +1284,7 @@ impl RegExp { let length_arg_str = arg_str.encode_utf16().count(); // 5. Let functionalReplace be IsCallable(replaceValue). - let mut replace_value = args.get(1).cloned().unwrap_or_default(); + let mut replace_value = args.get_or_undefined(1); let functional_replace = replace_value.is_function(); // 6. If functionalReplace is false, then @@ -1619,7 +1621,7 @@ impl RegExp { let mut length_a = 0; // 13. If limit is undefined, let lim be 2^32 - 1; else let lim be ℝ(? ToUint32(limit)). - let limit = args.get(1).cloned().unwrap_or_default(); + let limit = args.get_or_undefined(1); let lim = if limit.is_undefined() { u32::MAX } else { diff --git a/boa/src/builtins/set/mod.rs b/boa/src/builtins/set/mod.rs index 8dec1714aa2..867d834c6d6 100644 --- a/boa/src/builtins/set/mod.rs +++ b/boa/src/builtins/set/mod.rs @@ -22,6 +22,8 @@ use ordered_set::OrderedSet; pub mod set_iterator; use set_iterator::SetIterator; +use super::JsArgs; + pub mod ordered_set; #[cfg(test)] mod tests; @@ -139,7 +141,7 @@ impl Set { // 3 set.set_data(ObjectData::set(OrderedSet::default())); - let iterable = args.get(0).cloned().unwrap_or_default(); + let iterable = args.get_or_undefined(0); // 4 if iterable.is_null_or_undefined() { return Ok(set); @@ -206,7 +208,7 @@ impl Set { args: &[JsValue], context: &mut Context, ) -> JsResult { - let mut value = args.get(0).cloned().unwrap_or_default(); + let mut value = args.get_or_undefined(0); if let Some(object) = this.as_object() { if let Some(set) = object.borrow_mut().as_set_mut() { @@ -263,7 +265,7 @@ impl Set { args: &[JsValue], context: &mut Context, ) -> JsResult { - let value = args.get(0).cloned().unwrap_or_default(); + let value = args.get_or_undefined(0); let res = if let Some(object) = this.as_object() { if let Some(set) = object.borrow_mut().as_set_mut() { @@ -332,7 +334,7 @@ impl Set { } let callback_arg = &args[0]; - let this_arg = args.get(1).cloned().unwrap_or_else(JsValue::undefined); + let this_arg = args.get_or_undefined(1); // TODO: if condition should also check that we are not in strict mode let this_arg = if this_arg.is_undefined() { JsValue::Object(context.global_object()) @@ -380,7 +382,7 @@ impl Set { args: &[JsValue], context: &mut Context, ) -> JsResult { - let value = args.get(0).cloned().unwrap_or_default(); + let value = args.get_or_undefined(0); if let JsValue::Object(ref object) = this { let object = object.borrow(); diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index 9130f8f916f..ec1a2936fb5 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -29,6 +29,8 @@ use std::{ }; use unicode_normalization::UnicodeNormalization; +use super::JsArgs; + pub(crate) fn code_point_at(string: JsString, position: i32) -> Option<(u32, u8, bool)> { let size = string.encode_utf16().count() as i32; if position < 0 || position >= size { @@ -562,7 +564,7 @@ impl String { // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; - let arg = args.get(0).cloned().unwrap_or_else(JsValue::undefined); + let arg = args.get_or_undefined(0); if Self::is_regexp_object(&arg) { context.throw_type_error( @@ -576,12 +578,10 @@ impl String { let search_length = search_string.chars().count() as i32; // If less than 2 args specified, position is 'undefined', defaults to 0 - let position = if args.len() < 2 { - 0 + let position = if let Some(integer) = args.get(1) { + integer.to_integer(context)? as i32 } else { - args.get(1) - .expect("failed to get arg") - .to_integer(context)? as i32 + 0 }; let start = min(max(position, 0), length); @@ -617,7 +617,7 @@ impl String { // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; - let arg = args.get(0).cloned().unwrap_or_else(JsValue::undefined); + let arg = args.get_or_undefined(0); if Self::is_regexp_object(&arg) { context.throw_type_error( @@ -632,12 +632,10 @@ impl String { // If less than 2 args specified, end_position is 'undefined', defaults to // length of this - let end_position = if args.len() < 2 { - length + let end_position = if let Some(integer) = args.get(1) { + integer.to_integer(context)? as i32 } else { - args.get(1) - .expect("Could not get argument") - .to_integer(context)? as i32 + length }; let end = min(max(end_position, 0), length); @@ -671,7 +669,7 @@ impl String { // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; - let arg = args.get(0).cloned().unwrap_or_else(JsValue::undefined); + let arg = args.get_or_undefined(0); if Self::is_regexp_object(&arg) { context.throw_type_error( @@ -684,12 +682,11 @@ impl String { let length = primitive_val.chars().count() as i32; // If less than 2 args specified, position is 'undefined', defaults to 0 - let position = if args.len() < 2 { - 0 + + let position = if let Some(integer) = args.get(1) { + integer.to_integer(context)? as i32 } else { - args.get(1) - .expect("Could not get argument") - .to_integer(context)? as i32 + 0 }; let start = min(max(position, 0), length); @@ -730,9 +727,9 @@ impl String { // 1. Let O be ? RequireObjectCoercible(this value). this.require_object_coercible(context)?; - let search_value = args.get(0).cloned().unwrap_or_default(); + let search_value = args.get_or_undefined(0); - let replace_value = args.get(1).cloned().unwrap_or_default(); + let replace_value = args.get_or_undefined(1); // 2. If searchValue is neither undefined nor null, then if !search_value.is_null_or_undefined() { @@ -846,8 +843,8 @@ impl String { // 1. Let O be ? RequireObjectCoercible(this value). let o = this.require_object_coercible(context)?; - let search_value = args.get(0).cloned().unwrap_or_default(); - let replace_value = args.get(1).cloned().unwrap_or_default(); + let search_value = args.get_or_undefined(0); + let replace_value = args.get_or_undefined(1); // 2. If searchValue is neither undefined nor null, then if !search_value.is_null_or_undefined() { @@ -1109,7 +1106,7 @@ impl String { let o = this.require_object_coercible(context)?; // 2. If regexp is neither undefined nor null, then - let regexp = args.get(0).cloned().unwrap_or_default(); + let regexp = args.get_or_undefined(0); if !regexp.is_null_or_undefined() { // a. Let matcher be ? GetMethod(regexp, @@match). // b. If matcher is not undefined, then @@ -1370,21 +1367,17 @@ impl String { // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; // If no args are specified, start is 'undefined', defaults to 0 - let start = if args.is_empty() { - 0 + let start = if let Some(integer) = args.get(0) { + integer.to_integer(context)? as i32 } else { - args.get(0) - .expect("failed to get argument for String method") - .to_integer(context)? as i32 + 0 }; let length = primitive_val.encode_utf16().count() as i32; // If less than 2 args specified, end is the length of the this object converted to a String - let end = if args.len() < 2 { - length + let end = if let Some(integer) = args.get(1) { + integer.to_integer(context)? as i32 } else { - args.get(1) - .expect("Could not get argument") - .to_integer(context)? as i32 + length }; // Both start and end args replaced by 0 if they were negative // or by the length of the String if they were greater @@ -1425,24 +1418,20 @@ impl String { // Then we convert it into a Rust String by wrapping it in from_value let primitive_val = this.to_string(context)?; // If no args are specified, start is 'undefined', defaults to 0 - let mut start = if args.is_empty() { - 0 + let mut start = if let Some(integer) = args.get(0) { + integer.to_integer(context)? as i32 } else { - args.get(0) - .expect("failed to get argument for String method") - .to_integer(context)? as i32 + 0 }; let length = primitive_val.chars().count() as i32; // If less than 2 args specified, end is +infinity, the maximum number value. // Using i32::max_value() should be safe because the final length used is at most // the number of code units from start to the end of the string, // which should always be smaller or equals to both +infinity and i32::max_value - let end = if args.len() < 2 { - i32::MAX + let end = if let Some(integer) = args.get(1) { + integer.to_integer(context)? as i32 } else { - args.get(1) - .expect("Could not get argument") - .to_integer(context)? as i32 + i32::MAX }; // If start is negative it become the number of code units from the end of the string if start < 0 { @@ -1485,8 +1474,8 @@ impl String { // 1. Let O be ? RequireObjectCoercible(this value). let this = this.require_object_coercible(context)?; - let separator = args.get(0).cloned().unwrap_or_default(); - let limit = args.get(1).cloned().unwrap_or_default(); + let separator = args.get_or_undefined(0); + let limit = args.get_or_undefined(1); // 2. If separator is neither undefined nor null, then if !separator.is_null_or_undefined() { @@ -1661,7 +1650,7 @@ impl String { let o = this.require_object_coercible(context)?; // 2. If regexp is neither undefined nor null, then - let regexp = args.get(0).cloned().unwrap_or_default(); + let regexp = args.get_or_undefined(0); if !regexp.is_null_or_undefined() { // a. Let isRegExp be ? IsRegExp(regexp). // b. If isRegExp is true, then @@ -1722,7 +1711,7 @@ impl String { ) -> JsResult { let this = this.require_object_coercible(context)?; let s = this.to_string(context)?; - let form = args.get(0).cloned().unwrap_or_default(); + let form = args.get_or_undefined(0); let f_str; @@ -1762,7 +1751,7 @@ impl String { let o = this.require_object_coercible(context)?; // 2. If regexp is neither undefined nor null, then - let regexp = args.get(0).cloned().unwrap_or_default(); + let regexp = args.get_or_undefined(0); if !regexp.is_null_or_undefined() { // a. Let searcher be ? GetMethod(regexp, @@search). // b. If searcher is not undefined, then diff --git a/boa/src/builtins/symbol/mod.rs b/boa/src/builtins/symbol/mod.rs index 78c11defbf5..e7a91cd8989 100644 --- a/boa/src/builtins/symbol/mod.rs +++ b/boa/src/builtins/symbol/mod.rs @@ -31,6 +31,8 @@ use std::cell::RefCell; use rustc_hash::FxHashMap; +use super::JsArgs; + thread_local! { static GLOBAL_SYMBOL_REGISTRY: RefCell = RefCell::new(GlobalSymbolRegistry::new()); } @@ -276,7 +278,7 @@ impl Symbol { args: &[JsValue], context: &mut Context, ) -> JsResult { - let sym = args.get(0).cloned().unwrap_or_default(); + let sym = args.get_or_undefined(0); // 1. If Type(sym) is not Symbol, throw a TypeError exception. if let Some(sym) = sym.as_symbol() { // 2. For each element e of the GlobalSymbolRegistry List (see 20.4.2.2), do diff --git a/boa/src/class.rs b/boa/src/class.rs index 79938910016..4c4bf2041f6 100644 --- a/boa/src/class.rs +++ b/boa/src/class.rs @@ -7,6 +7,7 @@ //!# class::{Class, ClassBuilder}, //!# gc::{Finalize, Trace}, //!# Context, JsResult, JsValue, +//!# builtins::JsArgs, //!# }; //!# //! // This does not have to be an enum it can also be a struct. @@ -27,7 +28,7 @@ //! // This is what is called when we do `new Animal()` //! fn constructor(_this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { //! // This is equivalent to `String(arg)`. -//! let kind = args.get(0).cloned().unwrap_or_default().to_string(context)?; +//! let kind = args.get_or_undefined(0).to_string(context)?; //! //! let animal = match kind.as_str() { //! "cat" => Self::Cat,