Browse Source

Remove `toInteger` and document the `string` builtin (#1884)

The ECMAScript 2022 specification removes the `toInteger` method, and replaces it with `toIntegerOrInfinity`, which is arguably better for us since the `JsValue::toInteger` returns an `f64`, which is pretty confusing at times.

This pull request removes the `JsValue::to_integer` method, replaces all its calls by `JsValue::to_integer_or_infinity` or others per the spec and documents several methods from the `string` builtin.
pull/1889/head
jedel1043 3 years ago
parent
commit
00a19005e4
  1. 19
      boa_engine/src/builtins/console/mod.rs
  2. 68
      boa_engine/src/builtins/number/mod.rs
  3. 3
      boa_engine/src/builtins/regexp/mod.rs
  4. 848
      boa_engine/src/builtins/string/mod.rs
  5. 3
      boa_engine/src/builtins/string/string_iterator.rs
  6. 9
      boa_engine/src/builtins/string/tests.rs
  7. 5
      boa_engine/src/builtins/symbol/mod.rs
  8. 10
      boa_engine/src/symbol.rs
  9. 68
      boa_engine/src/tests.rs
  10. 69
      boa_engine/src/value/integer.rs
  11. 121
      boa_engine/src/value/mod.rs

19
boa_engine/src/builtins/console/mod.rs

@ -20,7 +20,7 @@ use crate::{
builtins::{BuiltIn, JsArgs}, builtins::{BuiltIn, JsArgs},
object::ObjectInitializer, object::ObjectInitializer,
property::Attribute, property::Attribute,
value::{display::display_obj, JsValue}, value::{display::display_obj, JsValue, Numeric},
Context, JsResult, JsString, Context, JsResult, JsString,
}; };
use boa_profiler::Profiler; use boa_profiler::Profiler;
@ -71,21 +71,16 @@ pub fn formatter(data: &[JsValue], context: &mut Context) -> JsResult<String> {
match fmt { match fmt {
/* integer */ /* integer */
'd' | 'i' => { 'd' | 'i' => {
let arg = data let arg = match data.get_or_undefined(arg_index).to_numeric(context)? {
.get(arg_index) Numeric::Number(r) => (r.floor() + 0.0).to_string(),
.cloned() Numeric::BigInt(int) => int.to_string(),
.unwrap_or_default() };
.to_integer(context)?; formatted.push_str(&arg);
formatted.push_str(&arg.to_string());
arg_index += 1; arg_index += 1;
} }
/* float */ /* float */
'f' => { 'f' => {
let arg = data let arg = data.get_or_undefined(arg_index).to_number(context)?;
.get(arg_index)
.cloned()
.unwrap_or_default()
.to_number(context)?;
formatted.push_str(&format!("{arg:.6}")); formatted.push_str(&format!("{arg:.6}"));
arg_index += 1; arg_index += 1;
} }

68
boa_engine/src/builtins/number/mod.rs

@ -192,7 +192,7 @@ impl Number {
let precision = match args.get(0) { let precision = match args.get(0) {
None | Some(JsValue::Undefined) => None, None | Some(JsValue::Undefined) => None,
// 2. Let f be ? ToIntegerOrInfinity(fractionDigits). // 2. Let f be ? ToIntegerOrInfinity(fractionDigits).
Some(n) => Some(n.to_integer(context)? as i32), Some(n) => Some(n.to_integer_or_infinity(context)?),
}; };
// 4. If x is not finite, return ! Number::toString(x). // 4. If x is not finite, return ! Number::toString(x).
if !this_num.is_finite() { if !this_num.is_finite() {
@ -200,15 +200,17 @@ impl Number {
} }
// Get rid of the '-' sign for -0.0 // Get rid of the '-' sign for -0.0
let this_num = if this_num == 0. { 0. } else { this_num }; let this_num = if this_num == 0. { 0. } else { this_num };
let this_str_num = if let Some(precision) = precision { let this_str_num = match precision {
None => f64_to_exponential(this_num),
Some(IntegerOrInfinity::Integer(precision)) if (0..=100).contains(&precision) =>
// 5. If f < 0 or f > 100, throw a RangeError exception. // 5. If f < 0 or f > 100, throw a RangeError exception.
if !(0..=100).contains(&precision) { {
f64_to_exponential_with_precision(this_num, precision as usize)
}
_ => {
return context return context
.throw_range_error("toExponential() argument must be between 0 and 100"); .throw_range_error("toExponential() argument must be between 0 and 100")
} }
f64_to_exponential_with_precision(this_num, precision as usize)
} else {
f64_to_exponential(this_num)
}; };
Ok(JsValue::new(this_str_num)) Ok(JsValue::new(this_str_num))
} }
@ -231,19 +233,19 @@ impl Number {
) -> JsResult<JsValue> { ) -> JsResult<JsValue> {
// 1. Let this_num be ? thisNumberValue(this value). // 1. Let this_num be ? thisNumberValue(this value).
let this_num = Self::this_number_value(this, context)?; let this_num = Self::this_number_value(this, context)?;
let precision = match args.get(0) {
// 2. Let f be ? ToIntegerOrInfinity(fractionDigits). // 2. Let f be ? ToIntegerOrInfinity(fractionDigits).
Some(n) => match n.to_integer(context)? as i32 { // 3. Assert: If fractionDigits is undefined, then f is 0.
0..=100 => n.to_integer(context)? as usize, let precision = args.get_or_undefined(0).to_integer_or_infinity(context)?;
// 4, 5. If f < 0 or f > 100, throw a RangeError exception.
_ => { // 4, 5. If f < 0 or f > 100, throw a RangeError exception.
return context let precision = precision
.throw_range_error("toFixed() digits argument must be between 0 and 100") .as_integer()
} .filter(|i| (0..=100).contains(i))
}, .ok_or_else(|| {
// 3. If fractionDigits is undefined, then f is 0. context.construct_range_error("toFixed() digits argument must be between 0 and 100")
None => 0, })? as usize;
};
// 6. If x is not finite, return ! Number::toString(x). // 6. If x is not finite, return ! Number::toString(x).
if !this_num.is_finite() { if !this_num.is_finite() {
Ok(JsValue::new(Self::to_native_string(this_num))) Ok(JsValue::new(Self::to_native_string(this_num)))
@ -642,21 +644,23 @@ impl Number {
// 1. Let x be ? thisNumberValue(this value). // 1. Let x be ? thisNumberValue(this value).
let x = Self::this_number_value(this, context)?; let x = Self::this_number_value(this, context)?;
// 2. If radix is undefined, let radixNumber be 10.
let radix = args.get_or_undefined(0); let radix = args.get_or_undefined(0);
let radix_number = if radix.is_undefined() { let radix_number = if radix.is_undefined() {
10.0 // 2. If radix is undefined, let radixNumber be 10.
// 3. Else, let radixNumber be ? ToInteger(radix). 10
} else { } else {
radix.to_integer(context)? // 3. Else, let radixMV be ? ToIntegerOrInfinity(radix).
}; radix
.to_integer_or_infinity(context)?
// 4. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception. .as_integer()
if !(2.0..=36.0).contains(&radix_number) { // 4. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception.
return context .filter(|i| (2..=36).contains(i))
.throw_range_error("radix must be an integer at least 2 and no greater than 36"); .ok_or_else(|| {
} context.construct_range_error(
let radix_number = radix_number as u8; "radix must be an integer at least 2 and no greater than 36",
)
})?
} as u8;
// 5. If radixNumber = 10, return ! ToString(x). // 5. If radixNumber = 10, return ! ToString(x).
if radix_number == 10 { if radix_number == 10 {

3
boa_engine/src/builtins/regexp/mod.rs

@ -1707,8 +1707,7 @@ fn advance_string_index(s: &JsString, index: usize, unicode: bool) -> usize {
} }
// 5. Let cp be ! CodePointAt(S, index). // 5. Let cp be ! CodePointAt(S, index).
let (_, offset, _) = let (_, offset, _) = crate::builtins::string::code_point_at(s, index);
crate::builtins::string::code_point_at(s, index as i64).expect("Failed to get code point");
index + offset as usize index + offset as usize
} }

848
boa_engine/src/builtins/string/mod.rs

File diff suppressed because it is too large Load Diff

3
boa_engine/src/builtins/string/string_iterator.rs

@ -57,8 +57,7 @@ impl StringIterator {
context, context,
)); ));
} }
let (_, code_unit_count, _) = code_point_at(&native_string, i64::from(position)) let (_, code_unit_count, _) = code_point_at(&native_string, position as usize);
.expect("Invalid code point position");
string_iterator.next_index += i32::from(code_unit_count); string_iterator.next_index += i32::from(code_unit_count);
let result_string = crate::builtins::string::String::substring( let result_string = crate::builtins::string::String::substring(
&string_iterator.string, &string_iterator.string,

9
boa_engine/src/builtins/string/tests.rs

@ -147,7 +147,8 @@ fn repeat_throws_when_count_is_negative() {
} }
"# "#
), ),
"\"RangeError: repeat count cannot be a negative number\"" "\"RangeError: repeat count must be a positive finite number \
that doesn't overflow the maximum string length (2^32 - 1)\""
); );
} }
@ -166,7 +167,8 @@ fn repeat_throws_when_count_is_infinity() {
} }
"# "#
), ),
"\"RangeError: repeat count cannot be infinity\"" "\"RangeError: repeat count must be a positive finite number \
that doesn't overflow the maximum string length (2^32 - 1)\""
); );
} }
@ -185,7 +187,8 @@ fn repeat_throws_when_count_overflows_max_length() {
} }
"# "#
), ),
"\"RangeError: repeat count must not overflow maximum string length\"" "\"RangeError: repeat count must be a positive finite number \
that doesn't overflow the maximum string length (2^32 - 1)\""
); );
} }

5
boa_engine/src/builtins/symbol/mod.rs

@ -210,8 +210,11 @@ impl Symbol {
_: &[JsValue], _: &[JsValue],
context: &mut Context, context: &mut Context,
) -> JsResult<JsValue> { ) -> JsResult<JsValue> {
// 1. Let sym be ? thisSymbolValue(this value).
let symbol = Self::this_symbol_value(this, context)?; let symbol = Self::this_symbol_value(this, context)?;
Ok(symbol.to_string().into())
// 2. Return SymbolDescriptiveString(sym).
Ok(symbol.descriptive_string().into())
} }
/// `Symbol.prototype.valueOf()` /// `Symbol.prototype.valueOf()`

10
boa_engine/src/symbol.rs

@ -289,6 +289,16 @@ impl JsSymbol {
pub fn hash(&self) -> u64 { pub fn hash(&self) -> u64 {
self.inner.hash self.inner.hash
} }
/// Abstract operation `SymbolDescriptiveString ( sym )`
///
/// More info:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-symboldescriptivestring
pub fn descriptive_string(&self) -> JsString {
self.to_string().into()
}
} }
impl Finalize for JsSymbol {} impl Finalize for JsSymbol {}

68
boa_engine/src/tests.rs

@ -1,5 +1,6 @@
use crate::{ use crate::{
builtins::Number, check_output, exec, forward, forward_val, Context, JsValue, TestAction, builtins::Number, check_output, exec, forward, forward_val, value::IntegerOrInfinity, Context,
JsValue, TestAction,
}; };
#[test] #[test]
@ -942,40 +943,49 @@ fn to_index() {
} }
#[test] #[test]
fn to_integer() { fn to_integer_or_infinity() {
let mut context = Context::default(); let mut context = Context::default();
assert!(Number::equal( assert_eq!(
JsValue::nan().to_integer(&mut context).unwrap(), JsValue::nan().to_integer_or_infinity(&mut context).unwrap(),
0.0 0
)); );
assert!(Number::equal( assert_eq!(
JsValue::new(f64::NEG_INFINITY) JsValue::new(f64::NEG_INFINITY)
.to_integer(&mut context) .to_integer_or_infinity(&mut context)
.unwrap(), .unwrap(),
f64::NEG_INFINITY IntegerOrInfinity::NegativeInfinity
)); );
assert!(Number::equal( assert_eq!(
JsValue::new(f64::INFINITY) JsValue::new(f64::INFINITY)
.to_integer(&mut context) .to_integer_or_infinity(&mut context)
.unwrap(), .unwrap(),
f64::INFINITY IntegerOrInfinity::PositiveInfinity
)); );
assert!(Number::equal( assert_eq!(
JsValue::new(0.0).to_integer(&mut context).unwrap(), JsValue::new(0.0)
0.0 .to_integer_or_infinity(&mut context)
)); .unwrap(),
let number = JsValue::new(-0.0).to_integer(&mut context).unwrap(); 0
assert!(!number.is_sign_negative()); );
assert!(Number::equal(number, 0.0)); assert_eq!(
assert!(Number::equal( JsValue::new(-0.0)
JsValue::new(20.9).to_integer(&mut context).unwrap(), .to_integer_or_infinity(&mut context)
20.0 .unwrap(),
)); 0
assert!(Number::equal( );
JsValue::new(-20.9).to_integer(&mut context).unwrap(), assert_eq!(
-20.0 JsValue::new(20.9)
)); .to_integer_or_infinity(&mut context)
.unwrap(),
20
);
assert_eq!(
JsValue::new(-20.9)
.to_integer_or_infinity(&mut context)
.unwrap(),
-20
);
} }
#[test] #[test]

69
boa_engine/src/value/integer.rs

@ -0,0 +1,69 @@
use std::cmp::Ordering;
/// Represents the result of `ToIntegerOrInfinity` operation
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum IntegerOrInfinity {
PositiveInfinity,
Integer(i64),
NegativeInfinity,
}
impl IntegerOrInfinity {
/// Clamps an `IntegerOrInfinity` between two `i64`, effectively converting
/// it to an i64.
pub fn clamp_finite(self, min: i64, max: i64) -> i64 {
assert!(min <= max);
match self {
IntegerOrInfinity::Integer(i) => i.clamp(min, max),
IntegerOrInfinity::PositiveInfinity => max,
IntegerOrInfinity::NegativeInfinity => min,
}
}
/// Gets the wrapped `i64` if the variant is an `Integer`.
pub fn as_integer(self) -> Option<i64> {
match self {
IntegerOrInfinity::Integer(i) => Some(i),
_ => None,
}
}
}
impl PartialEq<i64> for IntegerOrInfinity {
fn eq(&self, other: &i64) -> bool {
match self {
IntegerOrInfinity::Integer(i) => i == other,
_ => false,
}
}
}
impl PartialEq<IntegerOrInfinity> for i64 {
fn eq(&self, other: &IntegerOrInfinity) -> bool {
match other {
IntegerOrInfinity::Integer(i) => i == other,
_ => false,
}
}
}
impl PartialOrd<i64> for IntegerOrInfinity {
fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
match self {
IntegerOrInfinity::PositiveInfinity => Some(Ordering::Greater),
IntegerOrInfinity::Integer(i) => i.partial_cmp(other),
IntegerOrInfinity::NegativeInfinity => Some(Ordering::Less),
}
}
}
impl PartialOrd<IntegerOrInfinity> for i64 {
fn partial_cmp(&self, other: &IntegerOrInfinity) -> Option<Ordering> {
match other {
IntegerOrInfinity::PositiveInfinity => Some(Ordering::Less),
IntegerOrInfinity::Integer(i) => self.partial_cmp(i),
IntegerOrInfinity::NegativeInfinity => Some(Ordering::Greater),
}
}
}

121
boa_engine/src/value/mod.rs

@ -32,6 +32,7 @@ mod conversions;
pub(crate) mod display; pub(crate) mod display;
mod equality; mod equality;
mod hash; mod hash;
mod integer;
mod operations; mod operations;
mod serde_json; mod serde_json;
mod r#type; mod r#type;
@ -40,6 +41,7 @@ pub use conversions::*;
pub use display::ValueDisplay; pub use display::ValueDisplay;
pub use equality::*; pub use equality::*;
pub use hash::*; pub use hash::*;
pub use integer::IntegerOrInfinity;
pub use operations::*; pub use operations::*;
pub use r#type::Type; pub use r#type::Type;
@ -76,14 +78,6 @@ pub enum JsValue {
Symbol(JsSymbol), Symbol(JsSymbol),
} }
/// Represents the result of `ToIntegerOrInfinity` operation
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IntegerOrInfinity {
Integer(i64),
PositiveInfinity,
NegativeInfinity,
}
impl JsValue { impl JsValue {
/// Create a new [`JsValue`]. /// Create a new [`JsValue`].
#[inline] #[inline]
@ -614,7 +608,7 @@ impl JsValue {
} }
// 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))). // 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))).
let int = number.floor() as i64; let int = number.abs().floor().copysign(number) as i64;
// 4. Let int8bit be int modulo 2^8. // 4. Let int8bit be int modulo 2^8.
let int_8_bit = int % 2i64.pow(8); let int_8_bit = int % 2i64.pow(8);
@ -643,7 +637,7 @@ impl JsValue {
} }
// 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))). // 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))).
let int = number.floor() as i64; let int = number.abs().floor().copysign(number) as i64;
// 4. Let int8bit be int modulo 2^8. // 4. Let int8bit be int modulo 2^8.
let int_8_bit = int % 2i64.pow(8); let int_8_bit = int % 2i64.pow(8);
@ -715,7 +709,7 @@ impl JsValue {
} }
// 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))). // 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))).
let int = number.floor() as i64; let int = number.abs().floor().copysign(number) as i64;
// 4. Let int16bit be int modulo 2^16. // 4. Let int16bit be int modulo 2^16.
let int_16_bit = int % 2i64.pow(16); let int_16_bit = int % 2i64.pow(16);
@ -744,7 +738,7 @@ impl JsValue {
} }
// 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))). // 3. Let int be the mathematical value whose sign is the sign of number and whose magnitude is floor(abs(ℝ(number))).
let int = number.floor() as i64; let int = number.abs().floor().copysign(number) as i64;
// 4. Let int16bit be int modulo 2^16. // 4. Let int16bit be int modulo 2^16.
let int_16_bit = int % 2i64.pow(16); let int_16_bit = int % 2i64.pow(16);
@ -796,21 +790,29 @@ impl JsValue {
/// ///
/// See: <https://tc39.es/ecma262/#sec-toindex> /// See: <https://tc39.es/ecma262/#sec-toindex>
pub fn to_index(&self, context: &mut Context) -> JsResult<usize> { pub fn to_index(&self, context: &mut Context) -> JsResult<usize> {
// 1. If value is undefined, then
if self.is_undefined() { if self.is_undefined() {
// a. Return 0.
return Ok(0); return Ok(0);
} }
let integer_index = self.to_integer(context)?; // 2. Else,
// a. Let integer be ? ToIntegerOrInfinity(value).
let integer = self.to_integer_or_infinity(context)?;
if integer_index < 0.0 { // b. Let clamped be ! ToLength(𝔽(integer)).
return context.throw_range_error("Integer index must be >= 0"); let clamped = integer.clamp_finite(0, Number::MAX_SAFE_INTEGER as i64);
}
if integer_index > Number::MAX_SAFE_INTEGER { // c. If ! SameValue(𝔽(integer), clamped) is false, throw a RangeError exception.
return context.throw_range_error("Integer index must be less than 2**(53) - 1"); if integer != clamped {
return context.throw_range_error("Index must be between 0 and 2^53 - 1");
} }
Ok(integer_index as usize) // d. Assert: 0 ≤ integer ≤ 2^53 - 1.
debug_assert!(0 <= clamped && clamped <= Number::MAX_SAFE_INTEGER as i64);
// e. Return integer.
Ok(clamped as usize)
} }
/// Converts argument to an integer suitable for use as the length of an array-like object. /// Converts argument to an integer suitable for use as the length of an array-like object.
@ -818,37 +820,43 @@ impl JsValue {
/// See: <https://tc39.es/ecma262/#sec-tolength> /// See: <https://tc39.es/ecma262/#sec-tolength>
pub fn to_length(&self, context: &mut Context) -> JsResult<usize> { pub fn to_length(&self, context: &mut Context) -> JsResult<usize> {
// 1. Let len be ? ToInteger(argument). // 1. Let len be ? ToInteger(argument).
let len = self.to_integer(context)?;
// 2. If len ≤ +0, return +0. // 2. If len ≤ +0, return +0.
if len < 0.0 {
return Ok(0);
}
// 3. Return min(len, 2^53 - 1). // 3. Return min(len, 2^53 - 1).
Ok(len.min(Number::MAX_SAFE_INTEGER) as usize) Ok(self
.to_integer_or_infinity(context)?
.clamp_finite(0, Number::MAX_SAFE_INTEGER as i64) as usize)
} }
/// Converts a value to an integral Number value. /// Abstract operation `ToIntegerOrInfinity ( argument )`
///
/// This method converts a `Value` to an integer representing its `Number` value with
/// fractional part truncated, or to +∞ or -∞ when that `Number` value is infinite.
///
/// More information:
/// - [ECMAScript reference][spec]
/// ///
/// See: <https://tc39.es/ecma262/#sec-tointeger> /// [spec]: https://tc39.es/ecma262/#sec-tointegerorinfinity
pub fn to_integer(&self, context: &mut Context) -> JsResult<f64> { pub fn to_integer_or_infinity(&self, context: &mut Context) -> JsResult<IntegerOrInfinity> {
// 1. Let number be ? ToNumber(argument). // 1. Let number be ? ToNumber(argument).
let number = self.to_number(context)?; let number = self.to_number(context)?;
// 2. If number is +∞ or -∞, return number. if number.is_nan() || number == 0.0 {
if !number.is_finite() { // 2. If number is NaN, +0𝔽, or -0𝔽, return 0.
// 3. If number is NaN, +0, or -0, return +0. Ok(IntegerOrInfinity::Integer(0))
if number.is_nan() { } else if number == f64::INFINITY {
return Ok(0.0); // 3. If number is +∞𝔽, return +∞.
} Ok(IntegerOrInfinity::PositiveInfinity)
return Ok(number); } else if number == f64::NEG_INFINITY {
} // 4. If number is -∞𝔽, return -∞.
Ok(IntegerOrInfinity::NegativeInfinity)
} else {
// 5. Let integer be floor(abs(ℝ(number))).
// 6. If number < +0𝔽, set integer to -integer.
let integer = number.abs().floor().copysign(number) as i64;
// 4. Let integer be the Number value that is the same sign as number and whose magnitude is floor(abs(number)). // 7. Return integer.
// 5. If integer is -0, return +0. Ok(IntegerOrInfinity::Integer(integer))
// 6. Return integer. }
Ok(number.trunc() + 0.0) // We add 0.0 to convert -0.0 to +0.0
} }
/// Converts a value to a double precision floating point. /// Converts a value to a double precision floating point.
@ -918,37 +926,6 @@ impl JsValue {
.and_then(|obj| obj.to_property_descriptor(context)) .and_then(|obj| obj.to_property_descriptor(context))
} }
/// Converts argument to an integer, +∞, or -∞.
///
/// See: <https://tc39.es/ecma262/#sec-tointegerorinfinity>
pub fn to_integer_or_infinity(&self, context: &mut Context) -> JsResult<IntegerOrInfinity> {
// 1. Let number be ? ToNumber(argument).
let number = self.to_number(context)?;
// 2. If number is NaN, +0𝔽, or -0𝔽, return 0.
if number.is_nan() || number == 0.0 || number == -0.0 {
Ok(IntegerOrInfinity::Integer(0))
} else if number.is_infinite() && number.is_sign_positive() {
// 3. If number is +∞𝔽, return +∞.
Ok(IntegerOrInfinity::PositiveInfinity)
} else if number.is_infinite() && number.is_sign_negative() {
// 4. If number is -∞𝔽, return -∞.
Ok(IntegerOrInfinity::NegativeInfinity)
} else {
// 5. Let integer be floor(abs(ℝ(number))).
let integer = number.abs().floor();
let integer = integer.min(Number::MAX_SAFE_INTEGER) as i64;
// 6. If number < +0𝔽, set integer to -integer.
// 7. Return integer.
if number < 0.0 {
Ok(IntegerOrInfinity::Integer(-integer))
} else {
Ok(IntegerOrInfinity::Integer(integer))
}
}
}
/// `typeof` operator. Returns a string representing the type of the /// `typeof` operator. Returns a string representing the type of the
/// given ECMA Value. /// given ECMA Value.
/// ///

Loading…
Cancel
Save