Skip to content

Commit

Permalink
Merge 036c7d1 into 8b40e9e
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat authored Jun 26, 2020
2 parents 8b40e9e + 036c7d1 commit 5f3389e
Show file tree
Hide file tree
Showing 14 changed files with 599 additions and 195 deletions.
14 changes: 7 additions & 7 deletions boa/src/builtins/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,8 +514,8 @@ impl Array {
while i < len {
let element = this.get_field(i.to_string());
let arguments = [element, Value::from(i), this.clone()];
let result = interpreter.call(callback, &this_arg, &arguments)?.is_true();
if !result {
let result = interpreter.call(callback, &this_arg, &arguments)?;
if !result.to_boolean() {
return Ok(Value::from(false));
}
len = min(max_len, i32::from(&this.get_field("length")));
Expand Down Expand Up @@ -695,7 +695,7 @@ impl Array {
let element = this.get_field(i.to_string());
let arguments = [element.clone(), Value::from(i), this.clone()];
let result = interpreter.call(callback, &this_arg, &arguments)?;
if result.is_true() {
if result.to_boolean() {
return Ok(element);
}
}
Expand Down Expand Up @@ -737,7 +737,7 @@ impl Array {

let result = interpreter.call(predicate_arg, &this_arg, &arguments)?;

if result.is_true() {
if result.to_boolean() {
return Ok(Value::rational(f64::from(i)));
}
}
Expand Down Expand Up @@ -902,7 +902,7 @@ impl Array {
.call(&callback, &this_val, &args)
.unwrap_or_else(|_| Value::undefined());

if callback_result.is_true() {
if callback_result.to_boolean() {
Some(element)
} else {
None
Expand Down Expand Up @@ -946,8 +946,8 @@ impl Array {
while i < len {
let element = this.get_field(i.to_string());
let arguments = [element, Value::from(i), this.clone()];
let result = interpreter.call(callback, &this_arg, &arguments)?.is_true();
if result {
let result = interpreter.call(callback, &this_arg, &arguments)?;
if result.to_boolean() {
return Ok(Value::from(true));
}
// the length of the array must be updated because the callback can mutate it.
Expand Down
8 changes: 4 additions & 4 deletions boa/src/builtins/boolean/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ fn constructor_gives_true_instance() {
assert_eq!(true_bool.is_object(), true);

// Values should all be truthy
assert_eq!(true_val.is_true(), true);
assert_eq!(true_num.is_true(), true);
assert_eq!(true_string.is_true(), true);
assert_eq!(true_bool.is_true(), true);
assert_eq!(true_val.to_boolean(), true);
assert_eq!(true_num.to_boolean(), true);
assert_eq!(true_string.to_boolean(), true);
assert_eq!(true_bool.to_boolean(), true);
}

#[test]
Expand Down
91 changes: 91 additions & 0 deletions boa/src/builtins/number/conversions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use super::Number;

impl Number {
const SIGN_MASK: u64 = 0x8000000000000000;
const EXPONENT_MASK: u64 = 0x7FF0000000000000;
const SIGNIFICAND_MASK: u64 = 0x000FFFFFFFFFFFFF;
const HIDDEN_BIT: u64 = 0x0010000000000000;
const PHYSICAL_SIGNIFICAND_SIZE: i32 = 52; // Excludes the hidden bit.
const SIGNIFICAND_SIZE: i32 = 53;

const EXPONENT_BIAS: i32 = 0x3FF + Self::PHYSICAL_SIGNIFICAND_SIZE;
const DENORMAL_EXPONENT: i32 = -Self::EXPONENT_BIAS + 1;

#[inline]
pub(crate) fn is_denormal(self) -> bool {
(self.0.to_bits() & Self::EXPONENT_MASK) == 0
}

#[inline]
pub(crate) fn sign(self) -> i64 {
if (self.0.to_bits() & Self::SIGN_MASK) == 0 {
1
} else {
-1
}
}

#[inline]
pub(crate) fn significand(self) -> u64 {
let d64 = self.0.to_bits();
let significand = d64 & Self::SIGNIFICAND_MASK;

if !self.is_denormal() {
significand + Self::HIDDEN_BIT
} else {
significand
}
}

#[inline]
pub(crate) fn exponent(self) -> i32 {
if self.is_denormal() {
return Self::DENORMAL_EXPONENT;
}

let d64 = self.0.to_bits();
let biased_e = ((d64 & Self::EXPONENT_MASK) >> Self::PHYSICAL_SIGNIFICAND_SIZE) as i32;

biased_e - Self::EXPONENT_BIAS
}

/// Converts a 64-bit floating point number to an `i32` according to the [`ToInt32`][ToInt32] algorithm.
///
/// [ToInt32]: https://tc39.es/ecma262/#sec-toint32
#[inline]
#[allow(clippy::float_cmp)]
pub(crate) fn to_int32(self) -> i32 {
if self.0.is_finite() && self.0 <= f64::from(i32::MAX) && self.0 >= f64::from(i32::MIN) {
let i = self.0 as i32;
if f64::from(i) == self.0 {
return i;
}
}

// let exponent = ((bits >> 52) & 0x7ff);
let exponent = self.exponent();
let bits = if exponent < 0 {
if exponent <= -Self::SIGNIFICAND_SIZE {
return 0;
}

self.significand() >> -exponent
} else {
if exponent > 31 {
return 0;
}

(self.significand() << exponent) & 0xFFFFFFFF
};

(self.sign() * (bits as i64)) as i32
}

/// Converts a 64-bit floating point number to an `u32` according to the [`ToUint32`][ToUint32] algorithm.
///
/// [ToInt32]: https://tc39.es/ecma262/#sec-touint32
#[inline]
pub(crate) fn to_uint32(self) -> u32 {
self.to_int32() as u32
}
}
71 changes: 62 additions & 9 deletions boa/src/builtins/number/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
//! [spec]: https://tc39.es/ecma262/#sec-number-object
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number
#[cfg(test)]
mod tests;

use super::{
function::{make_builtin_fn, make_constructor_fn},
object::ObjectData,
Expand All @@ -27,11 +24,16 @@ use crate::{
};
use num_traits::float::FloatCore;

mod conversions;

#[cfg(test)]
mod tests;

const BUF_SIZE: usize = 2200;

/// `Number` implementation.
#[derive(Debug, Clone, Copy)]
pub(crate) struct Number;
pub(crate) struct Number(f64);

/// Maximum number of arguments expected to the builtin parseInt() function.
const PARSE_INT_MAX_ARG_COUNT: usize = 2;
Expand All @@ -46,14 +48,65 @@ impl Number {
/// The amount of arguments this function object takes.
pub(crate) const LENGTH: usize = 1;

/// The `Number.MAX_SAFE_INTEGER` constant represents the maximum safe integer in JavaScript (`2^53 - 1`).
///
/// /// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-number.max_safe_integer
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
pub(crate) const MAX_SAFE_INTEGER: f64 = 9_007_199_254_740_991_f64;

/// The `Number.MIN_SAFE_INTEGER` constant represents the minimum safe integer in JavaScript (`-(253 - 1)`).
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-number.min_safe_integer
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_SAFE_INTEGER
pub(crate) const MIN_SAFE_INTEGER: f64 = -9_007_199_254_740_991_f64;

/// The `Number.MAX_VALUE` property represents the maximum numeric value representable in JavaScript.
///
/// The `MAX_VALUE` property has a value of approximately `1.79E+308`, or `2^1024`.
/// Values larger than `MAX_VALUE` are represented as `Infinity`.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-number.max_value
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_VALUE
pub(crate) const MAX_VALUE: f64 = f64::MAX;

/// The `Number.MIN_VALUE` property represents the smallest positive numeric value representable in JavaScript.
///
/// The `MIN_VALUE` property is the number closest to `0`, not the most negative number, that JavaScript can represent.
/// It has a value of approximately `5e-324`. Values smaller than `MIN_VALUE` ("underflow values") are converted to `0`.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-number.min_value
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_VALUE
pub(crate) const MIN_VALUE: f64 = f64::MIN;

/// Create a new number.
#[inline]
pub(crate) fn new(value: f64) -> Self {
Self(value)
}

/// This function returns a `Result` of the number `Value`.
///
/// If the `Value` is a `Number` primitive of `Number` object the number is returned.
/// Otherwise an `TypeError` is thrown.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-thisnumbervalue
fn this_number_value(value: &Value, ctx: &mut Interpreter) -> Result<f64, Value> {
Expand Down Expand Up @@ -539,10 +592,10 @@ impl Number {
{
let mut properties = number.as_object_mut().expect("'Number' object");
properties.insert_field("EPSILON", Value::from(f64::EPSILON));
properties.insert_field("MAX_SAFE_INTEGER", Value::from(9_007_199_254_740_991_f64));
properties.insert_field("MIN_SAFE_INTEGER", Value::from(-9_007_199_254_740_991_f64));
properties.insert_field("MAX_VALUE", Value::from(f64::MAX));
properties.insert_field("MIN_VALUE", Value::from(f64::MIN));
properties.insert_field("MAX_SAFE_INTEGER", Value::from(Self::MAX_SAFE_INTEGER));
properties.insert_field("MIN_SAFE_INTEGER", Value::from(Self::MIN_SAFE_INTEGER));
properties.insert_field("MAX_VALUE", Value::from(Self::MAX_VALUE));
properties.insert_field("MIN_VALUE", Value::from(Self::MIN_VALUE));
properties.insert_field("NEGATIVE_INFINITY", Value::from(f64::NEG_INFINITY));
properties.insert_field("POSITIVE_INFINITY", Value::from(f64::INFINITY));
properties.insert_field("NaN", Value::from(f64::NAN));
Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/value/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl From<bool> for Value {

impl From<&Value> for bool {
fn from(value: &Value) -> Self {
value.is_true()
value.to_boolean()
}
}

Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/value/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ pub(crate) fn display_obj(v: &Value, print_internals: bool) -> String {
) -> String {
if let Value::Object(ref v) = *data {
// The in-memory address of the current object
let addr = address_of(v.borrow().deref());
let addr = address_of(v.as_ref());

// We need not continue if this object has already been
// printed up the current chain
Expand Down
33 changes: 7 additions & 26 deletions boa/src/builtins/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ use std::{
convert::TryFrom,
f64::NAN,
fmt::{self, Display},
ops::{Add, BitAnd, BitOr, BitXor, Deref, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub},
str::FromStr,
};

Expand Down Expand Up @@ -159,14 +158,6 @@ impl Value {
Self::Symbol(RcSymbol::from(symbol))
}

/// Helper function to convert the `Value` to a number and compute its power.
pub fn as_num_to_power(&self, other: Self) -> Self {
match (self, other) {
(Self::BigInt(ref a), Self::BigInt(ref b)) => Self::bigint(a.as_inner().clone().pow(b)),
(a, b) => Self::rational(a.to_number().powf(b.to_number())),
}
}

/// Returns a new empty object
pub fn new_object(global: Option<&Value>) -> Self {
let _timer = BoaProfiler::global().start_event("new_object", "value");
Expand Down Expand Up @@ -413,21 +404,6 @@ impl Value {
}
}

/// Returns true if the value is true.
///
/// [toBoolean](https://tc39.es/ecma262/#sec-toboolean)
pub fn is_true(&self) -> bool {
match *self {
Self::Object(_) => true,
Self::String(ref s) if !s.is_empty() => true,
Self::Rational(n) if n != 0.0 && !n.is_nan() => true,
Self::Integer(n) if n != 0 => true,
Self::Boolean(v) => v,
Self::BigInt(ref n) if *n.as_inner() != 0 => true,
_ => false,
}
}

/// Converts the value into a 64-bit floating point number
pub fn to_number(&self) -> f64 {
match *self {
Expand Down Expand Up @@ -473,7 +449,12 @@ impl Value {
}
}

/// Creates a new boolean value from the input
/// Converts the value to a `bool` type.
///
/// More information:
/// - [ECMAScript][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-toboolean
pub fn to_boolean(&self) -> bool {
match *self {
Self::Undefined | Self::Null => false,
Expand Down Expand Up @@ -713,7 +694,7 @@ impl Value {
#[inline]
pub fn set_data(&self, data: ObjectData) {
if let Self::Object(ref obj) = *self {
(*obj.deref().borrow_mut()).data = data;
obj.borrow_mut().data = data;
}
}

Expand Down
Loading

0 comments on commit 5f3389e

Please sign in to comment.