Skip to content

Commit

Permalink
Implement new get_or_undefined method for [JsValue] (#1492)
Browse files Browse the repository at this point in the history
* Create `JsArgs` trait

* Implement trait `JsArgs` for `[JsValue]`

* Replace calls to `get/unwrap_or` with `get_or_undefined`
  • Loading branch information
jedel1043 authored Sep 6, 2021
1 parent e9d7ac9 commit 2a8d343
Show file tree
Hide file tree
Showing 16 changed files with 206 additions and 191 deletions.
48 changes: 25 additions & 23 deletions boa/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -689,8 +691,8 @@ 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);
callback.call(&this_arg, &[k_value, k.into(), o.clone().into()], context)?;
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.
}
Expand Down Expand Up @@ -1024,7 +1026,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,
Expand All @@ -1038,7 +1040,7 @@ impl Array {
let k_value = o.get(k, context)?;
// ii. Let testResult be ! ToBoolean(? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »)).
let test_result = callback
.call(&this_arg, &[k_value, k.into(), o.clone().into()], context)?
.call(this_arg, &[k_value, k.into(), o.clone().into()], context)?
.to_boolean();
// iii. If testResult is false, return false.
if !test_result {
Expand Down Expand Up @@ -1072,15 +1074,15 @@ 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");
}

// 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,
Expand All @@ -1094,7 +1096,7 @@ impl Array {
let k_value = o.get(k, context)?;
// ii. Let mappedValue be ? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »).
let mapped_value =
context.call(&callback, &this_arg, &[k_value, k.into(), this.into()])?;
context.call(callback, this_arg, &[k_value, k.into(), this.into()])?;
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
a.create_data_property_or_throw(k, mapped_value, context)?;
}
Expand Down Expand Up @@ -1158,7 +1160,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 {
Expand Down Expand Up @@ -1234,7 +1236,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 {
Expand All @@ -1246,7 +1248,7 @@ impl Array {
let element_k = o.get(k, context)?;
// ii. Let same be IsStrictlyEqual(searchElement, elementK).
// iii. If same is true, return 𝔽(k).
if JsValue::strict_equals(&search_element, &element_k) {
if JsValue::strict_equals(search_element, &element_k) {
return Ok(JsValue::new(k));
}
}
Expand Down Expand Up @@ -1288,7 +1290,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;
Expand All @@ -1301,7 +1303,7 @@ impl Array {
// c. Let testResult be ! ToBoolean(? Call(predicate, thisArg, « kValue, 𝔽(k), O »)).
let test_result = predicate
.call(
&this_arg,
this_arg,
&[k_value.clone(), k.into(), o.clone().into()],
context,
)?
Expand Down Expand Up @@ -1349,7 +1351,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;
Expand All @@ -1361,7 +1363,7 @@ impl Array {
let k_value = o.get(pk, context)?;
// c. Let testResult be ! ToBoolean(? Call(predicate, thisArg, « kValue, 𝔽(k), O »)).
let test_result = predicate
.call(&this_arg, &[k_value, k.into(), o.clone().into()], context)?
.call(this_arg, &[k_value, k.into(), o.clone().into()], context)?
.to_boolean();
// d. If testResult is true, return 𝔽(k).
if test_result {
Expand Down Expand Up @@ -1453,7 +1455,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");
}
Expand All @@ -1469,7 +1471,7 @@ impl Array {
0,
1,
Some(mapper_function.as_object().unwrap()),
&args.get(1).cloned().unwrap_or_default(),
args.get_or_undefined(1),
context,
)?;

Expand Down Expand Up @@ -1624,7 +1626,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_ {
Expand Down Expand Up @@ -1695,14 +1697,14 @@ 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 {
// a. Let elementK be ? Get(O, ! ToString(𝔽(k))).
let element_k = o.get(k, context)?;
// b. If SameValueZero(searchElement, elementK) is true, return true.
if JsValue::same_value_zero(&search_element, &element_k) {
if JsValue::same_value_zero(search_element, &element_k) {
return Ok(JsValue::new(true));
}
// c. Set k to k + 1.
Expand Down Expand Up @@ -1992,7 +1994,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_arg = args.get_or_undefined(1);

if !callback.is_callable() {
return context.throw_type_error("the callback must be callable");
Expand All @@ -2016,7 +2018,7 @@ impl Array {
let args = [element.clone(), JsValue::new(idx), JsValue::new(o.clone())];

// ii. Let selected be ! ToBoolean(? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »)).
let selected = callback.call(&this_val, &args, context)?.to_boolean();
let selected = callback.call(this_arg, &args, context)?.to_boolean();

// iii. If selected is true, then
if selected {
Expand Down Expand Up @@ -2078,9 +2080,9 @@ 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)?
.call(this_arg, &[k_value, k.into(), o.clone().into()], context)?
.to_boolean();
// iii. If testResult is true, return true.
if test_result {
Expand Down
16 changes: 9 additions & 7 deletions boa/src/builtins/bigint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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);
Expand Down
7 changes: 3 additions & 4 deletions boa/src/builtins/console/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
mod tests;

use crate::{
builtins::BuiltIn,
builtins::{BuiltIn, JsArgs},
object::ObjectInitializer,
property::Attribute,
value::{display::display_obj, JsValue},
Expand Down Expand Up @@ -90,7 +90,7 @@ pub fn formatter(data: &[JsValue], context: &mut Context) -> JsResult<String> {
}
/* 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
}
Expand Down Expand Up @@ -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<JsValue> {
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(),
);

Expand Down
4 changes: 3 additions & 1 deletion boa/src/builtins/date/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
14 changes: 8 additions & 6 deletions boa/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ use dyn_clone::DynClone;
use sealed::Sealed;
use std::fmt::{self, Debug};

use super::JsArgs;

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -340,10 +342,10 @@ 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..])
context.call(this, this_arg, &args[start..])
}

/// `Function.prototype.apply`
Expand All @@ -361,15 +363,15 @@ 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, &[]);
return context.call(this, this_arg, &[]);
}
let arg_list = arg_array.create_list_from_array_like(&[], context)?;
// TODO?: 5. PrepareForTailCall
context.call(this, &this_arg, &arg_list)
context.call(this, this_arg, &arg_list)
}
}

Expand Down
8 changes: 5 additions & 3 deletions boa/src/builtins/json/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ use crate::{
};
use serde_json::{self, Value as JSONValue};

use super::JsArgs;

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -156,7 +158,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() {
Expand Down Expand Up @@ -212,7 +214,7 @@ impl Json {
}
}

let mut space = args.get(2).cloned().unwrap_or_default();
let mut space = args.get_or_undefined(2).clone();

// 5. If Type(space) is Object, then
if let Some(space_obj) = space.as_object() {
Expand Down Expand Up @@ -264,7 +266,7 @@ impl Json {

// 10. Perform ! CreateDataPropertyOrThrow(wrapper, the empty String, value).
wrapper
.create_data_property_or_throw("", args.get(0).cloned().unwrap_or_default(), context)
.create_data_property_or_throw("", args.get_or_undefined(0).clone(), context)
.expect("CreateDataPropertyOrThrow should never fail here");

// 11. Let state be the Record { [[ReplacerFunction]]: ReplacerFunction, [[Stack]]: stack, [[Indent]]: indent, [[Gap]]: gap, [[PropertyList]]: PropertyList }.
Expand Down
Loading

0 comments on commit 2a8d343

Please sign in to comment.