From 6e8e0d98fa4849a72db712b96899fdbf77f84932 Mon Sep 17 00:00:00 2001 From: Iban Eguia Moraza Date: Fri, 22 May 2020 22:28:23 +0200 Subject: [PATCH] Adding native error types, starting with `RangeError` --- boa/src/builtins/{error.rs => error/mod.rs} | 9 ++- boa/src/builtins/error/range.rs | 67 +++++++++++++++++++++ boa/src/builtins/number/mod.rs | 2 +- boa/src/exec/mod.rs | 13 ++-- 4 files changed, 82 insertions(+), 9 deletions(-) rename boa/src/builtins/{error.rs => error/mod.rs} (94%) create mode 100644 boa/src/builtins/error/range.rs diff --git a/boa/src/builtins/error.rs b/boa/src/builtins/error/mod.rs similarity index 94% rename from boa/src/builtins/error.rs rename to boa/src/builtins/error/mod.rs index 35f4e91c44c..2293ea5ba2a 100644 --- a/boa/src/builtins/error.rs +++ b/boa/src/builtins/error/mod.rs @@ -10,15 +10,22 @@ //! [spec]: https://tc39.es/ecma262/#sec-error-objects //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error -use super::function::make_constructor_fn; use crate::{ builtins::{ + function::make_constructor_fn, object::ObjectKind, value::{ResultValue, Value}, }, exec::Interpreter, }; +// mod eval; +pub mod range; +// mod reference; +// mod syntax; +// mod type_err; +// mod uri; + /// Create a new error object. pub fn make_error(this: &mut Value, args: &[Value], _: &mut Interpreter) -> ResultValue { if !args.is_empty() { diff --git a/boa/src/builtins/error/range.rs b/boa/src/builtins/error/range.rs new file mode 100644 index 00000000000..72492728322 --- /dev/null +++ b/boa/src/builtins/error/range.rs @@ -0,0 +1,67 @@ +//! This module implements the global `RangeError` object. +//! +//! Indicates a value that is not in the set or range of allowable values. +//! +//! More information: +//! - [MDN documentation][mdn] +//! - [ECMAScript reference][spec] +//! +//! [spec]: https://tc39.es/ecma262/#sec-native-error-types-used-in-this-standard-rangeerror +//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError + +use crate::{ + builtins::{ + function::make_constructor_fn, + object::ObjectKind, + value::{ResultValue, Value}, + }, + exec::Interpreter, +}; + +/// Create a new error object. +pub fn make_error(this: &mut Value, args: &[Value], _: &mut Interpreter) -> ResultValue { + if !args.is_empty() { + this.set_field_slice( + "message", + Value::from( + args.get(0) + .expect("failed getting error message") + .to_string(), + ), + ); + } + // This value is used by console.log and other routines to match Object type + // to its Javascript Identifier (global constructor method name) + this.set_kind(ObjectKind::Error); + Ok(Value::undefined()) +} + +/// `Error.prototype.toString()` +/// +/// The toString() method returns a string representing the specified Error object. +/// +/// More information: +/// - [MDN documentation][mdn] +/// - [ECMAScript reference][spec] +/// +/// [spec]: https://tc39.es/ecma262/#sec-error.prototype.tostring +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/toString +pub fn to_string(this: &mut Value, _: &[Value], _: &mut Interpreter) -> ResultValue { + let name = this.get_field_slice("name"); + let message = this.get_field_slice("message"); + Ok(Value::from(format!("{}: {}", name, message))) +} + +/// Create a new `RangeError` object. +pub fn create(global: &Value) -> Value { + let prototype = Value::new_object(Some(global)); + prototype.set_field_slice("message", Value::from("")); + prototype.set_field_slice("name", Value::from("RangeError")); + make_builtin_fn!(to_string, named "toString", of prototype); + make_constructor_fn(make_error, global, prototype) +} + +/// Initialise the global object with the `RangeError` object. +pub fn init(global: &Value) { + global.set_field_slice("RangeError", create(global)); +} diff --git a/boa/src/builtins/number/mod.rs b/boa/src/builtins/number/mod.rs index 0da8860f5ac..d1692f001f2 100644 --- a/boa/src/builtins/number/mod.rs +++ b/boa/src/builtins/number/mod.rs @@ -318,7 +318,7 @@ pub fn to_string(this: &mut Value, args: &[Value], _ctx: &mut Interpreter) -> Re // 4. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception. if radix_number < 2 || radix_number > 36 { - panic!("Radix must be between 2 and 36"); + panic!("RangeError: radix must be an integer at least 2 and no greater than 36"); } // 5. If radixNumber = 10, return ! ToString(x). diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 8e7524341cb..5ea5b5d4044 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -109,13 +109,12 @@ impl Interpreter { this: &mut Value, arguments_list: &[Value], ) -> ResultValue { - // All functions should be objects, and eventually will be. - // During this transition call will support both native functions and function objects - match (*f).deref() { - ValueData::Object(ref obj) => match (*obj).deref().borrow().func { - Some(ref func) => func.call(&mut f.clone(), arguments_list, self, this), - None => panic!("Expected function"), - }, + match *f.data() { + ValueData::Object(ref obj) => { + let obj = (**obj).borrow(); + let func = obj.func.as_ref().expect("Expected function"); + func.call(&mut f.clone(), arguments_list, self, this) + } _ => Err(Value::undefined()), } }