diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index bd5bb4923f..587be1561c 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -20,7 +20,7 @@ use crate::{ object::{ConstructorBuilder, FunctionBuilder, GcObject, ObjectData, PROTOTYPE}, property::{Attribute, DataDescriptor}, symbol::WellKnownSymbols, - value::{same_value_zero, IntegerOrInfinity, Value}, + value::{IntegerOrInfinity, Value}, BoaProfiler, Context, Result, }; use num_traits::*; @@ -1154,7 +1154,7 @@ impl Array { for idx in 0..length { let check_element = this.get_field(idx, context)?.clone(); - if same_value_zero(&check_element, &search_element) { + if Value::same_value_zero(&check_element, &search_element) { return Ok(Value::from(true)); } } diff --git a/boa/src/builtins/boolean/tests.rs b/boa/src/builtins/boolean/tests.rs index 59aaa5f723..20224b481c 100644 --- a/boa/src/builtins/boolean/tests.rs +++ b/boa/src/builtins/boolean/tests.rs @@ -1,4 +1,4 @@ -use crate::{forward, forward_val, value::same_value, Context}; +use crate::{forward, forward_val, Context, Value}; /// Test the correct type is returned from call and construct #[allow(clippy::unwrap_used)] @@ -58,7 +58,7 @@ fn instances_have_correct_proto_set() { let bool_instance = forward_val(&mut context, "boolInstance").expect("value expected"); let bool_prototype = forward_val(&mut context, "boolProto").expect("value expected"); - assert!(same_value( + assert!(Value::same_value( &bool_instance.as_object().unwrap().prototype_instance(), &bool_prototype )); diff --git a/boa/src/builtins/json/tests.rs b/boa/src/builtins/json/tests.rs index aec393982b..e91e07c4a6 100644 --- a/boa/src/builtins/json/tests.rs +++ b/boa/src/builtins/json/tests.rs @@ -1,4 +1,4 @@ -use crate::{forward, forward_val, value::same_value, Context, Value}; +use crate::{forward, forward_val, Context, Value}; #[test] fn json_sanity() { @@ -426,10 +426,13 @@ fn json_parse_sets_prototypes() { let global_array_prototype: Value = context.standard_objects().array_object().prototype().into(); assert_eq!( - same_value(&object_prototype, &global_object_prototype), + Value::same_value(&object_prototype, &global_object_prototype), + true + ); + assert_eq!( + Value::same_value(&array_prototype, &global_array_prototype), true ); - assert_eq!(same_value(&array_prototype, &global_array_prototype), true); } #[test] diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 82f90e1523..a0f685c90a 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -22,7 +22,7 @@ use crate::{ property::DataDescriptor, property::PropertyDescriptor, symbol::WellKnownSymbols, - value::{same_value, Type, Value}, + value::{Type, Value}, BoaProfiler, Context, Result, }; @@ -261,7 +261,7 @@ impl Object { let x = args.get(0).cloned().unwrap_or_else(Value::undefined); let y = args.get(1).cloned().unwrap_or_else(Value::undefined); - Ok(same_value(&x, &y).into()) + Ok(Value::same_value(&x, &y).into()) } /// Get the `prototype` of an object. @@ -351,7 +351,7 @@ impl Object { if v.is_null() { return Ok(Value::Boolean(false)); } - if same_value(&o, &v) { + if Value::same_value(&o, &v) { return Ok(Value::Boolean(true)); } } diff --git a/boa/src/object/internal_methods.rs b/boa/src/object/internal_methods.rs index 83811f0268..80246e0a55 100644 --- a/boa/src/object/internal_methods.rs +++ b/boa/src/object/internal_methods.rs @@ -8,7 +8,7 @@ use crate::{ object::{GcObject, Object, ObjectData}, property::{AccessorDescriptor, Attribute, DataDescriptor, PropertyDescriptor, PropertyKey}, - value::{same_value, Type, Value}, + value::{Type, Value}, BoaProfiler, Context, Result, }; @@ -245,7 +245,7 @@ impl GcObject { return false; } - if !same_value(&desc.value(), ¤t.value()) { + if !Value::same_value(&desc.value(), ¤t.value()) { return false; } } @@ -468,7 +468,7 @@ impl GcObject { pub fn set_prototype_of(&mut self, val: Value) -> bool { debug_assert!(val.is_object() || val.is_null()); let current = self.get_prototype_of(); - if same_value(¤t, &val) { + if Value::same_value(¤t, &val) { return true; } if !self.is_extensible() { @@ -479,7 +479,7 @@ impl GcObject { while !done { if p.is_null() { done = true - } else if same_value(&Value::from(self.clone()), &p) { + } else if Value::same_value(&Value::from(self.clone()), &p) { return false; } else { let prototype = p diff --git a/boa/src/object/mod.rs b/boa/src/object/mod.rs index 2eda6d077b..4b31d13869 100644 --- a/boa/src/object/mod.rs +++ b/boa/src/object/mod.rs @@ -15,7 +15,7 @@ use crate::{ gc::{Finalize, Trace}, property::{AccessorDescriptor, Attribute, DataDescriptor, PropertyDescriptor, PropertyKey}, symbol::RcSymbol, - value::{same_value, RcBigInt, RcString, Value}, + value::{RcBigInt, RcString, Value}, BoaProfiler, Context, }; use rustc_hash::FxHashMap; @@ -534,7 +534,7 @@ impl Object { } else { // If target is non-extensible, [[SetPrototypeOf]] must return false // unless V is the SameValue as the target's observed [[GetPrototypeOf]] value. - same_value(&prototype, &self.prototype) + Value::same_value(&prototype, &self.prototype) } } diff --git a/boa/src/value/equality.rs b/boa/src/value/equality.rs index ea941c08b1..9165e23ca3 100644 --- a/boa/src/value/equality.rs +++ b/boa/src/value/equality.rs @@ -28,7 +28,7 @@ impl Value { (Self::Null, Self::Null) => true, // 3. Return ! SameValueNonNumeric(x, y). - (_, _) => same_value_non_numeric(self, other), + (_, _) => Self::same_value_non_numeric(self, other), } } @@ -111,6 +111,74 @@ impl Value { _ => false, }) } + + /// The internal comparison abstract operation SameValue(x, y), + /// where x and y are ECMAScript language values, produces true or false. + /// + /// More information: + /// - [ECMAScript][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-samevalue + pub fn same_value(x: &Value, y: &Value) -> bool { + // 1. If Type(x) is different from Type(y), return false. + if x.get_type() != y.get_type() { + return false; + } + + match (x, y) { + // 2. If Type(x) is Number or BigInt, then + // a. Return ! Type(x)::SameValue(x, y). + (Value::BigInt(x), Value::BigInt(y)) => BigInt::same_value(x, y), + (Value::Rational(x), Value::Rational(y)) => Number::same_value(*x, *y), + (Value::Rational(x), Value::Integer(y)) => Number::same_value(*x, f64::from(*y)), + (Value::Integer(x), Value::Rational(y)) => Number::same_value(f64::from(*x), *y), + (Value::Integer(x), Value::Integer(y)) => x == y, + + // 3. Return ! SameValueNonNumeric(x, y). + (_, _) => Self::same_value_non_numeric(x, y), + } + } + + /// The internal comparison abstract operation `SameValueZero(x, y)`, + /// where `x` and `y` are ECMAScript language values, produces `true` or `false`. + /// + /// `SameValueZero` differs from SameValue only in its treatment of `+0` and `-0`. + /// + /// More information: + /// - [ECMAScript][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-samevaluezero + pub fn same_value_zero(x: &Value, y: &Value) -> bool { + if x.get_type() != y.get_type() { + return false; + } + + match (x, y) { + // 2. If Type(x) is Number or BigInt, then + // a. Return ! Type(x)::SameValueZero(x, y). + (Value::BigInt(x), Value::BigInt(y)) => BigInt::same_value_zero(x, y), + + (Value::Rational(x), Value::Rational(y)) => Number::same_value_zero(*x, *y), + (Value::Rational(x), Value::Integer(y)) => Number::same_value_zero(*x, f64::from(*y)), + (Value::Integer(x), Value::Rational(y)) => Number::same_value_zero(f64::from(*x), *y), + (Value::Integer(x), Value::Integer(y)) => x == y, + + // 3. Return ! SameValueNonNumeric(x, y). + (_, _) => Self::same_value_non_numeric(x, y), + } + } + + fn same_value_non_numeric(x: &Value, y: &Value) -> bool { + debug_assert!(x.get_type() == y.get_type()); + match (x, y) { + (Value::Null, Value::Null) | (Value::Undefined, Value::Undefined) => true, + (Value::String(ref x), Value::String(ref y)) => x == y, + (Value::Boolean(x), Value::Boolean(y)) => x == y, + (Value::Object(ref x), Value::Object(ref y)) => GcObject::equals(x, y), + (Value::Symbol(ref x), Value::Symbol(ref y)) => x == y, + _ => false, + } + } } /// This function takes a string and conversts it to BigInt type. @@ -128,71 +196,3 @@ pub fn string_to_bigint(string: &str) -> Option { BigInt::from_str(string) } - -/// The internal comparison abstract operation SameValue(x, y), -/// where x and y are ECMAScript language values, produces true or false. -/// -/// More information: -/// - [ECMAScript][spec] -/// -/// [spec]: https://tc39.es/ecma262/#sec-samevalue -pub fn same_value(x: &Value, y: &Value) -> bool { - // 1. If Type(x) is different from Type(y), return false. - if x.get_type() != y.get_type() { - return false; - } - - match (x, y) { - // 2. If Type(x) is Number or BigInt, then - // a. Return ! Type(x)::SameValue(x, y). - (Value::BigInt(x), Value::BigInt(y)) => BigInt::same_value(x, y), - (Value::Rational(x), Value::Rational(y)) => Number::same_value(*x, *y), - (Value::Rational(x), Value::Integer(y)) => Number::same_value(*x, f64::from(*y)), - (Value::Integer(x), Value::Rational(y)) => Number::same_value(f64::from(*x), *y), - (Value::Integer(x), Value::Integer(y)) => x == y, - - // 3. Return ! SameValueNonNumeric(x, y). - (_, _) => same_value_non_numeric(x, y), - } -} - -/// The internal comparison abstract operation `SameValueZero(x, y)`, -/// where `x` and `y` are ECMAScript language values, produces `true` or `false`. -/// -/// `SameValueZero` differs from SameValue only in its treatment of `+0` and `-0`. -/// -/// More information: -/// - [ECMAScript][spec] -/// -/// [spec]: https://tc39.es/ecma262/#sec-samevaluezero -pub fn same_value_zero(x: &Value, y: &Value) -> bool { - if x.get_type() != y.get_type() { - return false; - } - - match (x, y) { - // 2. If Type(x) is Number or BigInt, then - // a. Return ! Type(x)::SameValueZero(x, y). - (Value::BigInt(x), Value::BigInt(y)) => BigInt::same_value_zero(x, y), - - (Value::Rational(x), Value::Rational(y)) => Number::same_value_zero(*x, *y), - (Value::Rational(x), Value::Integer(y)) => Number::same_value_zero(*x, f64::from(*y)), - (Value::Integer(x), Value::Rational(y)) => Number::same_value_zero(f64::from(*x), *y), - (Value::Integer(x), Value::Integer(y)) => x == y, - - // 3. Return ! SameValueNonNumeric(x, y). - (_, _) => same_value_non_numeric(x, y), - } -} - -fn same_value_non_numeric(x: &Value, y: &Value) -> bool { - debug_assert!(x.get_type() == y.get_type()); - match (x, y) { - (Value::Null, Value::Null) | (Value::Undefined, Value::Undefined) => true, - (Value::String(ref x), Value::String(ref y)) => x == y, - (Value::Boolean(x), Value::Boolean(y)) => x == y, - (Value::Object(ref x), Value::Object(ref y)) => GcObject::equals(x, y), - (Value::Symbol(ref x), Value::Symbol(ref y)) => x == y, - _ => false, - } -} diff --git a/boa/src/value/hash.rs b/boa/src/value/hash.rs index c8bf15caa6..8a951d8228 100644 --- a/boa/src/value/hash.rs +++ b/boa/src/value/hash.rs @@ -5,7 +5,7 @@ use std::hash::{Hash, Hasher}; impl PartialEq for Value { fn eq(&self, other: &Self) -> bool { - same_value_zero(self, other) + Self::same_value_zero(self, other) } }