Browse Source

Make `same_value` and `same_value_zero` static methods. (#1271)

pull/1278/head
Halid Odat 3 years ago committed by GitHub
parent
commit
0dcf182ad9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      boa/src/builtins/array/mod.rs
  2. 4
      boa/src/builtins/boolean/tests.rs
  3. 9
      boa/src/builtins/json/tests.rs
  4. 6
      boa/src/builtins/object/mod.rs
  5. 8
      boa/src/object/internal_methods.rs
  6. 4
      boa/src/object/mod.rs
  7. 138
      boa/src/value/equality.rs
  8. 2
      boa/src/value/hash.rs

4
boa/src/builtins/array/mod.rs

@ -20,7 +20,7 @@ use crate::{
object::{ConstructorBuilder, FunctionBuilder, GcObject, ObjectData, PROTOTYPE}, object::{ConstructorBuilder, FunctionBuilder, GcObject, ObjectData, PROTOTYPE},
property::{Attribute, DataDescriptor}, property::{Attribute, DataDescriptor},
symbol::WellKnownSymbols, symbol::WellKnownSymbols,
value::{same_value_zero, IntegerOrInfinity, Value}, value::{IntegerOrInfinity, Value},
BoaProfiler, Context, Result, BoaProfiler, Context, Result,
}; };
use num_traits::*; use num_traits::*;
@ -1154,7 +1154,7 @@ impl Array {
for idx in 0..length { for idx in 0..length {
let check_element = this.get_field(idx, context)?.clone(); 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)); return Ok(Value::from(true));
} }
} }

4
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 /// Test the correct type is returned from call and construct
#[allow(clippy::unwrap_used)] #[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_instance = forward_val(&mut context, "boolInstance").expect("value expected");
let bool_prototype = forward_val(&mut context, "boolProto").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_instance.as_object().unwrap().prototype_instance(),
&bool_prototype &bool_prototype
)); ));

9
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] #[test]
fn json_sanity() { fn json_sanity() {
@ -426,10 +426,13 @@ fn json_parse_sets_prototypes() {
let global_array_prototype: Value = let global_array_prototype: Value =
context.standard_objects().array_object().prototype().into(); context.standard_objects().array_object().prototype().into();
assert_eq!( 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 true
); );
assert_eq!(same_value(&array_prototype, &global_array_prototype), true);
} }
#[test] #[test]

6
boa/src/builtins/object/mod.rs

@ -22,7 +22,7 @@ use crate::{
property::DataDescriptor, property::DataDescriptor,
property::PropertyDescriptor, property::PropertyDescriptor,
symbol::WellKnownSymbols, symbol::WellKnownSymbols,
value::{same_value, Type, Value}, value::{Type, Value},
BoaProfiler, Context, Result, BoaProfiler, Context, Result,
}; };
@ -261,7 +261,7 @@ impl Object {
let x = args.get(0).cloned().unwrap_or_else(Value::undefined); let x = args.get(0).cloned().unwrap_or_else(Value::undefined);
let y = args.get(1).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. /// Get the `prototype` of an object.
@ -351,7 +351,7 @@ impl Object {
if v.is_null() { if v.is_null() {
return Ok(Value::Boolean(false)); return Ok(Value::Boolean(false));
} }
if same_value(&o, &v) { if Value::same_value(&o, &v) {
return Ok(Value::Boolean(true)); return Ok(Value::Boolean(true));
} }
} }

8
boa/src/object/internal_methods.rs

@ -8,7 +8,7 @@
use crate::{ use crate::{
object::{GcObject, Object, ObjectData}, object::{GcObject, Object, ObjectData},
property::{AccessorDescriptor, Attribute, DataDescriptor, PropertyDescriptor, PropertyKey}, property::{AccessorDescriptor, Attribute, DataDescriptor, PropertyDescriptor, PropertyKey},
value::{same_value, Type, Value}, value::{Type, Value},
BoaProfiler, Context, Result, BoaProfiler, Context, Result,
}; };
@ -245,7 +245,7 @@ impl GcObject {
return false; return false;
} }
if !same_value(&desc.value(), &current.value()) { if !Value::same_value(&desc.value(), &current.value()) {
return false; return false;
} }
} }
@ -468,7 +468,7 @@ impl GcObject {
pub fn set_prototype_of(&mut self, val: Value) -> bool { pub fn set_prototype_of(&mut self, val: Value) -> bool {
debug_assert!(val.is_object() || val.is_null()); debug_assert!(val.is_object() || val.is_null());
let current = self.get_prototype_of(); let current = self.get_prototype_of();
if same_value(&current, &val) { if Value::same_value(&current, &val) {
return true; return true;
} }
if !self.is_extensible() { if !self.is_extensible() {
@ -479,7 +479,7 @@ impl GcObject {
while !done { while !done {
if p.is_null() { if p.is_null() {
done = true done = true
} else if same_value(&Value::from(self.clone()), &p) { } else if Value::same_value(&Value::from(self.clone()), &p) {
return false; return false;
} else { } else {
let prototype = p let prototype = p

4
boa/src/object/mod.rs

@ -15,7 +15,7 @@ use crate::{
gc::{Finalize, Trace}, gc::{Finalize, Trace},
property::{AccessorDescriptor, Attribute, DataDescriptor, PropertyDescriptor, PropertyKey}, property::{AccessorDescriptor, Attribute, DataDescriptor, PropertyDescriptor, PropertyKey},
symbol::RcSymbol, symbol::RcSymbol,
value::{same_value, RcBigInt, RcString, Value}, value::{RcBigInt, RcString, Value},
BoaProfiler, Context, BoaProfiler, Context,
}; };
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@ -534,7 +534,7 @@ impl Object {
} else { } else {
// If target is non-extensible, [[SetPrototypeOf]] must return false // If target is non-extensible, [[SetPrototypeOf]] must return false
// unless V is the SameValue as the target's observed [[GetPrototypeOf]] value. // unless V is the SameValue as the target's observed [[GetPrototypeOf]] value.
same_value(&prototype, &self.prototype) Value::same_value(&prototype, &self.prototype)
} }
} }

138
boa/src/value/equality.rs

@ -28,7 +28,7 @@ impl Value {
(Self::Null, Self::Null) => true, (Self::Null, Self::Null) => true,
// 3. Return ! SameValueNonNumeric(x, y). // 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, _ => 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. /// This function takes a string and conversts it to BigInt type.
@ -128,71 +196,3 @@ pub fn string_to_bigint(string: &str) -> Option<BigInt> {
BigInt::from_str(string) 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,
}
}

2
boa/src/value/hash.rs

@ -5,7 +5,7 @@ use std::hash::{Hash, Hasher};
impl PartialEq for Value { impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
same_value_zero(self, other) Self::same_value_zero(self, other)
} }
} }

Loading…
Cancel
Save