Rust编写的JavaScript引擎,该项目是一个试验性质的项目。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

146 lines
4.6 KiB

//! This module implements the global `Error` object.
//!
//! Error objects are thrown when runtime errors occur.
//! The Error object can also be used as a base object for user-defined exceptions.
//!
//! More information:
//! - [MDN documentation][mdn]
//! - [ECMAScript reference][spec]
//!
//! [spec]: https://tc39.es/ecma262/#sec-error-objects
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
use crate::{
builtins::BuiltIn,
object::{ConstructorBuilder, ObjectData, PROTOTYPE},
profiler::BoaProfiler,
property::Attribute,
Context, Result, Value,
};
pub(crate) mod eval;
pub(crate) mod range;
pub(crate) mod reference;
pub(crate) mod syntax;
pub(crate) mod r#type;
pub(crate) mod uri;
#[cfg(test)]
mod tests;
pub(crate) use self::eval::EvalError;
pub(crate) use self::r#type::TypeError;
pub(crate) use self::range::RangeError;
pub(crate) use self::reference::ReferenceError;
pub(crate) use self::syntax::SyntaxError;
pub(crate) use self::uri::UriError;
/// Built-in `Error` object.
#[derive(Debug, Clone, Copy)]
pub(crate) struct Error;
impl BuiltIn for Error {
const NAME: &'static str = "Error";
fn attribute() -> Attribute {
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE
}
fn init(context: &mut Context) -> (&'static str, Value, Attribute) {
let _timer = BoaProfiler::global().start_event(Self::NAME, "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
let error_object = ConstructorBuilder::with_standard_object(
context,
Self::constructor,
context.standard_objects().error_object().clone(),
)
.name(Self::NAME)
.length(Self::LENGTH)
.property("name", Self::NAME, attribute)
.property("message", "", attribute)
.method(Self::to_string, "toString", 0)
.build();
(Self::NAME, error_object.into(), Self::attribute())
}
}
impl Error {
/// The amount of arguments this function object takes.
pub(crate) const LENGTH: usize = 1;
/// `Error( message )`
///
/// Create a new error object.
pub(crate) fn constructor(
new_target: &Value,
args: &[Value],
context: &mut Context,
) -> Result<Value> {
let prototype = new_target
.as_object()
.and_then(|obj| {
obj.get(&PROTOTYPE.into(), obj.clone().into(), context)
.map(|o| o.as_object())
.transpose()
})
.transpose()?
.unwrap_or_else(|| context.standard_objects().error_object().prototype());
let mut obj = context.construct_object();
obj.set_prototype_instance(prototype.into());
let this = Value::from(obj);
if let Some(message) = args.get(0) {
if !message.is_undefined() {
this.set_field("message", message.to_string(context)?, context)?;
}
}
// This value is used by console.log and other routines to match Object type
// to its Javascript Identifier (global constructor method name)
this.set_data(ObjectData::Error);
Ok(this)
}
/// `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
#[allow(clippy::wrong_self_convention)]
pub(crate) fn to_string(this: &Value, _: &[Value], context: &mut Context) -> Result<Value> {
if !this.is_object() {
return context.throw_type_error("'this' is not an Object");
}
let name = this.get_field("name", context)?;
let name_to_string;
let name = if name.is_undefined() {
"Error"
} else {
name_to_string = name.to_string(context)?;
name_to_string.as_str()
};
let message = this.get_field("message", context)?;
let message_to_string;
let message = if message.is_undefined() {
""
} else {
message_to_string = message.to_string(context)?;
message_to_string.as_str()
};
if name.is_empty() {
Ok(message.into())
} else if message.is_empty() {
Ok(name.into())
} else {
Ok(format!("{}: {}", name, message).into())
}
}
}