Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Privatize JsValue's internals and expose it through a JsVariant (with immutable reference) #4080

Merged
merged 21 commits into from
Dec 19, 2024
Merged
2 changes: 1 addition & 1 deletion cli/src/debug/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use boa_engine::{
/// Trigger garbage collection.
fn collect(_: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
boa_gc::force_collect();
Ok(JsValue::undefined())
Ok(JsValue::UNDEFINED)
}

pub(super) fn create_object(context: &mut Context) -> JsObject {
Expand Down
6 changes: 3 additions & 3 deletions cli/src/debug/limits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn get_loop(_: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsVal
fn set_loop(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let value = args.get_or_undefined(0).to_length(context)?;
context.runtime_limits_mut().set_loop_iteration_limit(value);
Ok(JsValue::undefined())
Ok(JsValue::UNDEFINED)
}

fn get_stack(_: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Expand All @@ -29,7 +29,7 @@ fn set_stack(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<J
.into());
};
context.runtime_limits_mut().set_stack_size_limit(value);
Ok(JsValue::undefined())
Ok(JsValue::UNDEFINED)
}

fn get_recursion(_: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Expand All @@ -45,7 +45,7 @@ fn set_recursion(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResu
.into());
};
context.runtime_limits_mut().set_recursion_limit(value);
Ok(JsValue::undefined())
Ok(JsValue::UNDEFINED)
}

pub(super) fn create_object(context: &mut Context) -> JsObject {
Expand Down
4 changes: 2 additions & 2 deletions cli/src/debug/optimizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn set_constant_folding(_: &JsValue, args: &[JsValue], context: &mut Context) ->
let mut options = context.optimizer_options();
options.set(OptimizerOptions::CONSTANT_FOLDING, value);
context.set_optimizer_options(options);
Ok(JsValue::undefined())
Ok(JsValue::UNDEFINED)
}

fn get_statistics(_: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
Expand All @@ -33,7 +33,7 @@ fn set_statistics(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsRes
let mut options = context.optimizer_options();
options.set(OptimizerOptions::STATISTICS, value);
context.set_optimizer_options(options);
Ok(JsValue::undefined())
Ok(JsValue::UNDEFINED)
}

pub(super) fn create_object(context: &mut Context) -> JsObject {
Expand Down
22 changes: 12 additions & 10 deletions core/engine/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ use std::cmp::{min, Ordering};
use super::{BuiltInBuilder, BuiltInConstructor, IntrinsicObject};

mod array_iterator;
use crate::value::JsVariant;
pub(crate) use array_iterator::ArrayIterator;

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -537,9 +539,9 @@ impl Array {
// 3. Else,
// a. If IsCallable(mapfn) is false, throw a TypeError exception.
// b. Let mapping be true.
let mapping = match mapfn {
JsValue::Undefined => None,
JsValue::Object(o) if o.is_callable() => Some(o),
let mapping = match mapfn.variant() {
JsVariant::Undefined => None,
JsVariant::Object(o) if o.is_callable() => Some(o),
_ => {
return Err(JsNativeError::typ()
.with_message(format!("`{}` is not callable", mapfn.type_of()))
Expand Down Expand Up @@ -2665,9 +2667,9 @@ impl Array {
context: &mut Context,
) -> JsResult<JsValue> {
// 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
let comparefn = match args.get_or_undefined(0) {
JsValue::Object(ref obj) if obj.is_callable() => Some(obj),
JsValue::Undefined => None,
let comparefn = match args.get_or_undefined(0).variant() {
JsVariant::Object(obj) if obj.is_callable() => Some(obj),
JsVariant::Undefined => None,
_ => {
return Err(JsNativeError::typ()
.with_message("The comparison function must be either a function or undefined")
Expand Down Expand Up @@ -2728,9 +2730,9 @@ impl Array {
context: &mut Context,
) -> JsResult<JsValue> {
// 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
let comparefn = match args.get_or_undefined(0) {
JsValue::Object(ref obj) if obj.is_callable() => Some(obj),
JsValue::Undefined => None,
let comparefn = match args.get_or_undefined(0).variant() {
JsVariant::Object(obj) if obj.is_callable() => Some(obj),
JsVariant::Undefined => None,
_ => {
return Err(JsNativeError::typ()
.with_message("The comparison function must be either a function or undefined")
Expand Down Expand Up @@ -3319,7 +3321,7 @@ fn compare_array_elements(
let args = [x.clone(), y.clone()];
// a. Let v be ? ToNumber(? Call(comparefn, undefined, « x, y »)).
let v = cmp
.call(&JsValue::Undefined, &args, context)?
.call(&JsValue::UNDEFINED, &args, context)?
.to_number(context)?;
// b. If v is NaN, return +0𝔽.
// c. Return v.
Expand Down
6 changes: 4 additions & 2 deletions core/engine/src/builtins/array/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,8 @@ fn array_spread_non_iterable() {
fn get_relative_start() {
#[track_caller]
fn assert(context: &mut Context, arg: Option<&JsValue>, len: u64, expected: u64) {
let arg = arg.unwrap_or(&JsValue::Undefined);
const UNDEFINED: &JsValue = &JsValue::UNDEFINED;
let arg = arg.unwrap_or(UNDEFINED);
assert_eq!(
Array::get_relative_start(context, arg, len).unwrap(),
expected
Expand All @@ -902,7 +903,8 @@ fn get_relative_start() {
fn get_relative_end() {
#[track_caller]
fn assert(context: &mut Context, arg: Option<&JsValue>, len: u64, expected: u64) {
let arg = arg.unwrap_or(&JsValue::Undefined);
const UNDEFINED: &JsValue = &JsValue::UNDEFINED;
let arg = arg.unwrap_or(UNDEFINED);
assert_eq!(
Array::get_relative_end(context, arg, len).unwrap(),
expected
Expand Down
2 changes: 1 addition & 1 deletion core/engine/src/builtins/array_buffer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ impl ArrayBuffer {
// 8. If allocatingResizableBuffer is true, then
// c. Set obj.[[ArrayBufferMaxByteLength]] to maxByteLength.
max_byte_len,
detach_key: JsValue::Undefined,
detach_key: JsValue::UNDEFINED,
},
);

Expand Down
2 changes: 1 addition & 1 deletion core/engine/src/builtins/date/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ impl Date {

// 4. If t is NaN, return NaN.
if t.is_nan() {
return Ok(JsValue::from(f64::NAN));
return Ok(JsValue::NAN);
};

if LOCAL {
Expand Down
14 changes: 7 additions & 7 deletions core/engine/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,12 +511,12 @@ impl BuiltInFunctionObject {
// It is a Syntax Error if FormalParameters Contains YieldExpression is true.
if generator && contains(&parameters, ContainsSymbol::YieldExpression) {
return Err(JsNativeError::syntax().with_message(
if r#async {
"yield expression is not allowed in formal parameter list of async generator"
} else {
"yield expression is not allowed in formal parameter list of generator"
}
).into());
if r#async {
"yield expression is not allowed in formal parameter list of async generator"
} else {
"yield expression is not allowed in formal parameter list of generator"
}
).into());
}

// It is a Syntax Error if FormalParameters Contains AwaitExpression is true.
Expand Down Expand Up @@ -735,7 +735,7 @@ impl BuiltInFunctionObject {
let f = BoundFunction::create(target.clone(), this_arg, bound_args, context)?;

// 4. Let L be 0.
let mut l = JsValue::new(0);
let mut l = JsValue::ZERO;

// 5. Let targetHasLength be ? HasOwnProperty(Target, "length").
// 6. If targetHasLength is true, then
Expand Down
2 changes: 1 addition & 1 deletion core/engine/src/builtins/intl/locale/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ impl Locale {
.keywords
.get(&key!("kn"))
.map(Value::as_tinystr_slice);
Ok(JsValue::Boolean(match kn {
Ok(JsValue::new(match kn {
Some([]) => true,
Some([kn]) if kn == "true" => true,
_ => false,
Expand Down
2 changes: 1 addition & 1 deletion core/engine/src/builtins/intl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ impl Intl {
let ll = locale::canonicalize_locale_list(locales, context)?;

// 2. Return CreateArrayFromList(ll).
Ok(JsValue::Object(Array::create_array_from_list(
Ok(JsValue::new(Array::create_array_from_list(
ll.into_iter().map(|loc| js_string!(loc.to_string()).into()),
context,
)))
Expand Down
30 changes: 15 additions & 15 deletions core/engine/src/builtins/intl/number_format/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ use num_bigint::BigInt;
use num_traits::Num;
pub(crate) use options::*;

use super::{
locale::{canonicalize_locale_list, filter_locales, resolve_locale, validate_extension},
options::{coerce_options_to_object, IntlOptions},
Service,
};
use crate::value::JsVariant;
use crate::{
builtins::{
builder::BuiltInBuilder, options::get_option, string::is_trimmable_whitespace,
Expand All @@ -41,12 +47,6 @@ use crate::{
NativeFunction,
};

use super::{
locale::{canonicalize_locale_list, filter_locales, resolve_locale, validate_extension},
options::{coerce_options_to_object, IntlOptions},
Service,
};

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -338,7 +338,7 @@ impl BuiltInConstructor for NumberFormat {
break 'block default_use_grouping;
}
// 3. If value is true, return true.
if let &JsValue::Boolean(true) = &value {
if let Some(true) = value.as_boolean() {
break 'block GroupingStrategy::Always;
}

Expand Down Expand Up @@ -750,8 +750,8 @@ fn unwrap_number_format(nf: &JsValue, context: &mut Context) -> JsResult<JsObjec

// a. Return ? Get(nf, %Intl%.[[FallbackSymbol]]).
let nf = nf_o.get(fallback_symbol, context)?;
if let JsValue::Object(nf) = nf {
if let Ok(nf) = nf.downcast::<NumberFormat>() {
if let Some(nf) = nf.as_object() {
if let Ok(nf) = nf.clone().downcast::<NumberFormat>() {
return Ok(nf);
}
}
Expand All @@ -771,16 +771,16 @@ fn to_intl_mathematical_value(value: &JsValue, context: &mut Context) -> JsResul

// TODO: Add support in `FixedDecimal` for infinity and NaN, which
// should remove the returned errors.
match prim_value {
match prim_value.variant() {
// 2. If Type(primValue) is BigInt, return ℝ(primValue).
JsValue::BigInt(bi) => {
JsVariant::BigInt(bi) => {
let bi = bi.to_string();
FixedDecimal::try_from(bi.as_bytes())
.map_err(|err| JsNativeError::range().with_message(err.to_string()).into())
}
// 3. If Type(primValue) is String, then
// a. Let str be primValue.
JsValue::String(s) => {
JsVariant::String(s) => {
// 5. Let text be StringToCodePoints(str).
// 6. Let literal be ParseText(text, StringNumericLiteral).
// 7. If literal is a List of errors, return not-a-number.
Expand All @@ -791,18 +791,18 @@ fn to_intl_mathematical_value(value: &JsValue, context: &mut Context) -> JsResul
// c. If rounded is +∞𝔽, return positive-infinity.
// d. If rounded is +0𝔽 and intlMV < 0, return negative-zero.
// e. If rounded is +0𝔽, return 0.
js_string_to_fixed_decimal(&s).ok_or_else(|| {
js_string_to_fixed_decimal(s).ok_or_else(|| {
JsNativeError::syntax()
.with_message("could not parse the provided string")
.into()
})
}
// 4. Else,
other => {
_ => {
// a. Let x be ? ToNumber(primValue).
// b. If x is -0𝔽, return negative-zero.
// c. Let str be Number::toString(x, 10).
let x = other.to_number(context)?;
let x = prim_value.to_number(context)?;

FixedDecimal::try_from_f64(x, FloatPrecision::Floating)
.map_err(|err| JsNativeError::range().with_message(err.to_string()).into())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ impl AsyncFromSyncIterator {
// b. Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »).
promise_capability
.resolve()
.call(&JsValue::Undefined, &[iter_result], context)
.call(&JsValue::UNDEFINED, &[iter_result], context)
.expect("cannot fail according to spec");

// c. Return promiseCapability.[[Promise]].
Expand Down
4 changes: 2 additions & 2 deletions core/engine/src/builtins/iterable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,8 @@ impl IteratorResult {
/// Gets a new `IteratorResult` from a value. Returns `Err` if
/// the value is not a [`JsObject`]
pub(crate) fn from_value(value: JsValue) -> JsResult<Self> {
if let JsValue::Object(o) = value {
Ok(Self { object: o })
if let Some(object) = value.into_object() {
Ok(Self { object })
} else {
Err(JsNativeError::typ()
.with_message("next value should be an object")
Expand Down
21 changes: 10 additions & 11 deletions core/engine/src/builtins/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ mod map_iterator;
pub(crate) use map_iterator::MapIterator;

pub mod ordered_map;
use crate::value::JsVariant;
use ordered_map::OrderedMap;

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -238,11 +240,11 @@ impl Map {
// 2. Perform ? RequireInternalSlot(M, [[MapData]]).
// 3. Let entries be the List that is M.[[MapData]].
if let Some(mut map) = object.downcast_mut::<OrderedMap<JsValue>>() {
let key = match key {
JsValue::Rational(r) => {
let key = match key.variant() {
JsVariant::Float64(r) => {
// 5. If key is -0𝔽, set key to +0𝔽.
if r.is_zero() {
JsValue::Rational(0f64)
JsValue::ZERO
} else {
key.clone()
}
Expand Down Expand Up @@ -306,10 +308,9 @@ impl Map {
/// [spec]: https://tc39.es/ecma262/#sec-map.prototype.delete
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete
pub(crate) fn delete(this: &JsValue, args: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
const JS_ZERO: &JsValue = &JsValue::Integer(0);
let key = args.get_or_undefined(0);
let key = match key.as_number() {
Some(n) if n.is_zero() => JS_ZERO,
Some(n) if n.is_zero() => &JsValue::ZERO,
_ => key,
};

Expand Down Expand Up @@ -342,15 +343,14 @@ impl Map {
/// [spec]: https://tc39.es/ecma262/#sec-map.prototype.get
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get
pub(crate) fn get(this: &JsValue, args: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
const JS_ZERO: &JsValue = &JsValue::Integer(0);
let key = args.get_or_undefined(0);
let key = match key.as_number() {
Some(n) if n.is_zero() => JS_ZERO,
Some(n) if n.is_zero() => &JsValue::ZERO,
_ => key,
};

// 1. Let M be the this value.
if let JsValue::Object(ref object) = this {
if let Some(object) = this.as_object() {
// 2. Perform ? RequireInternalSlot(M, [[MapData]]).
// 3. Let entries be the List that is M.[[MapData]].
if let Some(map) = object.downcast_ref::<OrderedMap<JsValue>>() {
Expand Down Expand Up @@ -407,15 +407,14 @@ impl Map {
/// [spec]: https://tc39.es/ecma262/#sec-map.prototype.has
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has
pub(crate) fn has(this: &JsValue, args: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
const JS_ZERO: &JsValue = &JsValue::Integer(0);
let key = args.get_or_undefined(0);
let key = match key.as_number() {
Some(n) if n.is_zero() => JS_ZERO,
Some(n) if n.is_zero() => &JsValue::ZERO,
_ => key,
};

// 1. Let M be the this value.
if let JsValue::Object(ref object) = this {
if let Some(object) = this.as_object() {
// 2. Perform ? RequireInternalSlot(M, [[MapData]]).
// 3. Let entries be the List that is M.[[MapData]].
if let Some(map) = object.downcast_ref::<OrderedMap<JsValue>>() {
Expand Down
2 changes: 1 addition & 1 deletion core/engine/src/builtins/number/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ pub(crate) fn parse_int(_: &JsValue, args: &[JsValue], context: &mut Context) ->
return Ok(JsValue::new(-0_f64));
}

return Ok(JsValue::new(0_f64));
return Ok(JsValue::ZERO);
}

// 16. Return 𝔽(sign × mathInt).
Expand Down
Loading
Loading