Skip to content

Commit

Permalink
Added initial RangeError exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
Razican committed May 23, 2020
1 parent 6e8e0d9 commit 2d94859
Show file tree
Hide file tree
Showing 29 changed files with 3,241 additions and 3,042 deletions.
1,732 changes: 892 additions & 840 deletions boa/src/builtins/array/mod.rs

Large diffs are not rendered by default.

165 changes: 92 additions & 73 deletions boa/src/builtins/bigint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,93 +14,112 @@
use crate::{
builtins::{
function::make_constructor_fn,
function::{make_builtin_fn, make_constructor_fn},
value::{ResultValue, Value},
},
exec::Interpreter,
syntax::ast::bigint::BigInt,
syntax::ast::bigint::BigInt as AstBigInt,
};

#[cfg(test)]
mod tests;

/// `BigInt()`
///
/// The `BigInt()` constructor is used to create BigInt objects.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-bigint-objects
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/BigInt
pub fn make_bigint(_this: &mut Value, args: &[Value], _ctx: &mut Interpreter) -> ResultValue {
let data = match args.get(0) {
Some(ref value) => {
if let Some(bigint) = value.to_bigint() {
Value::from(bigint)
} else {
panic!("RangeError: The value cannot be converted to a BigInt because it is not an integer");
/// `BigInt` implementation.
#[derive(Debug, Clone, Copy)]
pub(crate) struct BigInt;

impl BigInt {
/// `BigInt()`
///
/// The `BigInt()` constructor is used to create BigInt objects.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-bigint-objects
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/BigInt
pub(crate) fn make_bigint(
_this: &mut Value,
args: &[Value],
_ctx: &mut Interpreter,
) -> ResultValue {
let data = match args.get(0) {
Some(ref value) => {
if let Some(bigint) = value.to_bigint() {
Value::from(bigint)
} else {
panic!("RangeError: The value cannot be converted to a BigInt because it is not an integer");
}
}
}
None => Value::from(BigInt::from(0)),
};
Ok(data)
}
None => Value::from(AstBigInt::from(0)),
};
Ok(data)
}

/// `BigInt.prototype.toString( [radix] )`
///
/// The `toString()` method returns a string representing the specified BigInt object.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-bigint.prototype.tostring
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toString
pub fn to_string(this: &mut Value, args: &[Value], _ctx: &mut Interpreter) -> ResultValue {
let radix = if !args.is_empty() {
args[0].to_integer()
} else {
10
};
if radix < 2 && radix > 36 {
panic!("RangeError: toString() radix argument must be between 2 and 36");
/// `BigInt.prototype.toString( [radix] )`
///
/// The `toString()` method returns a string representing the specified BigInt object.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-bigint.prototype.tostring
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toString
#[allow(clippy::wrong_self_convention)]
pub(crate) fn to_string(
this: &mut Value,
args: &[Value],
_ctx: &mut Interpreter,
) -> ResultValue {
let radix = if !args.is_empty() {
args[0].to_integer()
} else {
10
};
if radix < 2 && radix > 36 {
panic!("RangeError: toString() radix argument must be between 2 and 36");
}
Ok(Value::from(
this.to_bigint().unwrap().to_str_radix(radix as u32),
))
}
Ok(Value::from(
this.to_bigint().unwrap().to_str_radix(radix as u32),
))
}

// /// `BigInt.prototype.valueOf()`
// ///
// /// The `valueOf()` method returns the wrapped primitive value of a Number object.
// ///
// /// More information:
// /// - [ECMAScript reference][spec]
// /// - [MDN documentation][mdn]
// ///
/// [spec]: https://tc39.es/ecma262/#sec-bigint.prototype.valueof
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/valueOf
pub fn value_of(this: &mut Value, _args: &[Value], _ctx: &mut Interpreter) -> ResultValue {
Ok(Value::from(
this.to_bigint().expect("BigInt.prototype.valueOf"),
))
}
// /// `BigInt.prototype.valueOf()`
// ///
// /// The `valueOf()` method returns the wrapped primitive value of a Number object.
// ///
// /// More information:
// /// - [ECMAScript reference][spec]
// /// - [MDN documentation][mdn]
// ///
/// [spec]: https://tc39.es/ecma262/#sec-bigint.prototype.valueof
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/valueOf
pub(crate) fn value_of(
this: &mut Value,
_args: &[Value],
_ctx: &mut Interpreter,
) -> ResultValue {
Ok(Value::from(
this.to_bigint().expect("BigInt.prototype.valueOf"),
))
}

/// Create a new `Number` object
pub fn create(global: &Value) -> Value {
let prototype = Value::new_object(Some(global));
prototype.set_internal_slot("BigIntData", Value::from(BigInt::from(0)));
/// Create a new `Number` object
pub(crate) fn create(global: &Value) -> Value {
let prototype = Value::new_object(Some(global));
prototype.set_internal_slot("BigIntData", Value::from(AstBigInt::from(0)));

make_builtin_fn!(to_string, named "toString", with length 1, of prototype);
make_builtin_fn!(value_of, named "valueOf", of prototype);
make_builtin_fn(Self::to_string, "toString", &prototype, 1);
make_builtin_fn(Self::value_of, "valueOf", &prototype, 0);

make_constructor_fn(make_bigint, global, prototype)
}
make_constructor_fn(Self::make_bigint, global, prototype)
}

/// Initialise the `BigInt` object on the global object.
#[inline]
pub fn init(global: &Value) {
global.set_field_slice("BigInt", create(global));
/// Initialise the `BigInt` object on the global object.
#[inline]
pub(crate) fn init(global: &Value) {
global.set_field("BigInt", Self::create(global));
}
}
166 changes: 89 additions & 77 deletions boa/src/builtins/boolean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#[cfg(test)]
mod tests;

use super::function::make_constructor_fn;
use super::function::{make_builtin_fn, make_constructor_fn};
use crate::{
builtins::{
object::{internal_methods_trait::ObjectInternalMethods, ObjectKind},
Expand All @@ -22,93 +22,105 @@ use crate::{
};
use std::{borrow::Borrow, ops::Deref};

/// `[[Construct]]` Create a new boolean object
///
/// `[[Call]]` Creates a new boolean primitive
pub fn construct_boolean(this: &mut Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
this.set_kind(ObjectKind::Boolean);
/// Boolean implementation.
#[derive(Debug, Clone, Copy)]
pub(crate) struct Boolean;

// Get the argument, if any
if let Some(ref value) = args.get(0) {
this.set_internal_slot("BooleanData", to_boolean(value));
} else {
this.set_internal_slot("BooleanData", to_boolean(&Value::from(false)));
}
impl Boolean {
/// `[[Construct]]` Create a new boolean object
///
/// `[[Call]]` Creates a new boolean primitive
pub(crate) fn construct_boolean(
this: &mut Value,
args: &[Value],
_: &mut Interpreter,
) -> ResultValue {
this.set_kind(ObjectKind::Boolean);

// Get the argument, if any
if let Some(ref value) = args.get(0) {
this.set_internal_slot("BooleanData", Self::to_boolean(value));
} else {
this.set_internal_slot("BooleanData", Self::to_boolean(&Value::from(false)));
}

match args.get(0) {
Some(ref value) => Ok(to_boolean(value)),
None => Ok(to_boolean(&Value::from(false))),
match args.get(0) {
Some(ref value) => Ok(Self::to_boolean(value)),
None => Ok(Self::to_boolean(&Value::from(false))),
}
}
}

/// The `toString()` method returns a string representing the specified `Boolean` object.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-boolean-object
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean/toString
pub fn to_string(this: &mut Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
let b = this_boolean_value(this);
Ok(Value::from(b.to_string()))
}
/// The `toString()` method returns a string representing the specified `Boolean` object.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-boolean-object
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean/toString
#[allow(clippy::wrong_self_convention)]
pub(crate) fn to_string(this: &mut Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
let b = Self::this_boolean_value(this);
Ok(Value::from(b.to_string()))
}

/// The valueOf() method returns the primitive value of a `Boolean` object.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-boolean.prototype.valueof
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean/valueOf
pub fn value_of(this: &mut Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(this_boolean_value(this))
}
/// The valueOf() method returns the primitive value of a `Boolean` object.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-boolean.prototype.valueof
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean/valueOf
pub(crate) fn value_of(this: &mut Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
Ok(Self::this_boolean_value(this))
}

// === Utility Functions ===
/// [toBoolean](https://tc39.es/ecma262/#sec-toboolean)
/// Creates a new boolean value from the input
pub fn to_boolean(value: &Value) -> Value {
match *value.deref().borrow() {
ValueData::Object(_) => Value::from(true),
ValueData::String(ref s) if !s.is_empty() => Value::from(true),
ValueData::Rational(n) if n != 0.0 && !n.is_nan() => Value::from(true),
ValueData::Integer(n) if n != 0 => Value::from(true),
ValueData::Boolean(v) => Value::from(v),
_ => Value::from(false),
// === Utility Functions ===
/// [toBoolean](https://tc39.es/ecma262/#sec-toboolean)
/// Creates a new boolean value from the input
#[allow(clippy::wrong_self_convention)]
pub(crate) fn to_boolean(value: &Value) -> Value {
match *value.deref().borrow() {
ValueData::Object(_) => Value::from(true),
ValueData::String(ref s) if !s.is_empty() => Value::from(true),
ValueData::Rational(n) if n != 0.0 && !n.is_nan() => Value::from(true),
ValueData::Integer(n) if n != 0 => Value::from(true),
ValueData::Boolean(v) => Value::from(v),
_ => Value::from(false),
}
}
}

/// An Utility function used to get the internal BooleanData.
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-thisbooleanvalue
pub fn this_boolean_value(value: &Value) -> Value {
match *value.deref().borrow() {
ValueData::Boolean(v) => Value::from(v),
ValueData::Object(ref v) => (v).deref().borrow().get_internal_slot("BooleanData"),
_ => Value::from(false),
/// An Utility function used to get the internal BooleanData.
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-thisbooleanvalue
pub(crate) fn this_boolean_value(value: &Value) -> Value {
match *value.deref().borrow() {
ValueData::Boolean(v) => Value::from(v),
ValueData::Object(ref v) => (v).deref().borrow().get_internal_slot("BooleanData"),
_ => Value::from(false),
}
}
}

/// Create a new `Boolean` object.
pub fn create(global: &Value) -> Value {
// Create Prototype
// https://tc39.es/ecma262/#sec-properties-of-the-boolean-prototype-object
let prototype = Value::new_object(Some(global));
prototype.set_internal_slot("BooleanData", to_boolean(&Value::from(false)));
/// Create a new `Boolean` object.
pub(crate) fn create(global: &Value) -> Value {
// Create Prototype
// https://tc39.es/ecma262/#sec-properties-of-the-boolean-prototype-object
let prototype = Value::new_object(Some(global));
prototype.set_internal_slot("BooleanData", Self::to_boolean(&Value::from(false)));

make_builtin_fn!(to_string, named "toString", of prototype);
make_builtin_fn!(value_of, named "valueOf", of prototype);
make_builtin_fn(Self::to_string, "toString", &prototype, 0);
make_builtin_fn(Self::value_of, "valueOf", &prototype, 0);

make_constructor_fn(construct_boolean, global, prototype)
}
make_constructor_fn(Self::construct_boolean, global, prototype)
}

/// Initialise the `Boolean` object on the global object.
#[inline]
pub fn init(global: &Value) {
global.set_field_slice("Boolean", create(global));
/// Initialise the `Boolean` object on the global object.
#[inline]
pub(crate) fn init(global: &Value) {
global.set_field("Boolean", Self::create(global));
}
}
2 changes: 1 addition & 1 deletion boa/src/builtins/boolean/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{builtins::value::same_value, exec::Interpreter, forward, forward_val
#[test]
fn check_boolean_constructor_is_function() {
let global = Value::new_object(None);
let boolean_constructor = create(&global);
let boolean_constructor = Boolean::create(&global);
assert_eq!(boolean_constructor.is_function(), true);
}

Expand Down
Loading

0 comments on commit 2d94859

Please sign in to comment.