From 4c3058b6bfcda706df71a05776fd869df7bca218 Mon Sep 17 00:00:00 2001 From: Halid Odat Date: Thu, 3 Mar 2022 20:49:31 +0000 Subject: [PATCH] Implement `AggregateError` (#1888) It changes the following: - Implement `AggregateError` global object --- boa_engine/src/builtins/error/aggregate.rs | 114 +++++++++++++++++++++ boa_engine/src/builtins/error/mod.rs | 2 + boa_engine/src/builtins/mod.rs | 6 +- boa_engine/src/context.rs | 7 ++ 4 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 boa_engine/src/builtins/error/aggregate.rs diff --git a/boa_engine/src/builtins/error/aggregate.rs b/boa_engine/src/builtins/error/aggregate.rs new file mode 100644 index 00000000000..6a7e212fe88 --- /dev/null +++ b/boa_engine/src/builtins/error/aggregate.rs @@ -0,0 +1,114 @@ +//! This module implements the global `AggregateError` object. +//! +//! More information: +//! - [MDN documentation][mdn] +//! - [ECMAScript reference][spec] +//! +//! [spec]: https://tc39.es/ecma262/#sec-aggregate-error +//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError + +use crate::{ + builtins::{iterable::iterable_to_list, Array, BuiltIn, JsArgs}, + context::StandardObjects, + object::{ + internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData, + }, + property::{Attribute, PropertyDescriptorBuilder}, + Context, JsResult, JsValue, +}; +use boa_profiler::Profiler; + +use super::Error; + +#[derive(Debug, Clone, Copy)] +pub(crate) struct AggregateError; + +impl BuiltIn for AggregateError { + const NAME: &'static str = "AggregateError"; + + const ATTRIBUTE: Attribute = Attribute::WRITABLE + .union(Attribute::NON_ENUMERABLE) + .union(Attribute::CONFIGURABLE); + + fn init(context: &mut Context) -> JsValue { + let _timer = Profiler::global().start_event(Self::NAME, "init"); + + let error_constructor = context.standard_objects().error_object().constructor(); + let error_prototype = context.standard_objects().error_object().prototype(); + + let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; + let aggregate_error_object = ConstructorBuilder::with_standard_object( + context, + Self::constructor, + context.standard_objects().aggregate_error_object().clone(), + ) + .name(Self::NAME) + .length(Self::LENGTH) + .inherit(error_prototype) + .custom_prototype(error_constructor) + .property("name", Self::NAME, attribute) + .property("message", "", attribute) + .build(); + + aggregate_error_object.into() + } +} + +impl AggregateError { + /// The amount of arguments this function object takes. + pub(crate) const LENGTH: usize = 1; + + /// Create a new aggregate error object. + pub(crate) fn constructor( + new_target: &JsValue, + args: &[JsValue], + context: &mut Context, + ) -> JsResult { + // 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget. + // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%AggregateError.prototype%", « [[ErrorData]] »). + let prototype = get_prototype_from_constructor( + new_target, + StandardObjects::aggregate_error_object, + context, + )?; + let o = JsObject::from_proto_and_data(prototype, ObjectData::error()); + + // 3. If message is not undefined, then + let message = args.get_or_undefined(1); + if !message.is_undefined() { + // a. Let msg be ? ToString(message). + let msg = message.to_string(context)?; + + // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). + o.create_non_enumerable_data_property_or_throw("message", msg, context); + } + + // 4. Perform ? InstallErrorCause(O, options). + Error::install_error_cause(&o, args.get_or_undefined(2), context)?; + + // 5. Let errorsList be ? IterableToList(errors). + let errors = args.get_or_undefined(0); + let errors_list = iterable_to_list(context, errors, None)?; + // 6. Perform ! DefinePropertyOrThrow(O, "errors", + // PropertyDescriptor { + // [[Configurable]]: true, + // [[Enumerable]]: false, + // [[Writable]]: true, + // [[Value]]: CreateArrayFromList(errorsList) + // }). + o.define_property_or_throw( + "errors", + PropertyDescriptorBuilder::new() + .configurable(true) + .enumerable(false) + .writable(true) + .value(Array::create_array_from_list(errors_list, context)) + .build(), + context, + ) + .expect("should not fail according to spec"); + + // 5. Return O. + Ok(o.into()) + } +} diff --git a/boa_engine/src/builtins/error/mod.rs b/boa_engine/src/builtins/error/mod.rs index eb9a79f2676..58d1a377f0c 100644 --- a/boa_engine/src/builtins/error/mod.rs +++ b/boa_engine/src/builtins/error/mod.rs @@ -21,6 +21,7 @@ use crate::{ }; use boa_profiler::Profiler; +pub(crate) mod aggregate; pub(crate) mod eval; pub(crate) mod range; pub(crate) mod reference; @@ -31,6 +32,7 @@ pub(crate) mod uri; #[cfg(test)] mod tests; +pub(crate) use self::aggregate::AggregateError; pub(crate) use self::eval::EvalError; pub(crate) use self::r#type::TypeError; pub(crate) use self::range::RangeError; diff --git a/boa_engine/src/builtins/mod.rs b/boa_engine/src/builtins/mod.rs index 65795897ed4..d5b8213e1da 100644 --- a/boa_engine/src/builtins/mod.rs +++ b/boa_engine/src/builtins/mod.rs @@ -38,7 +38,10 @@ pub(crate) use self::{ boolean::Boolean, dataview::DataView, date::Date, - error::{Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, UriError}, + error::{ + AggregateError, Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, + UriError, + }, function::BuiltInFunctionObject, global_this::GlobalThis, infinity::Infinity, @@ -163,6 +166,7 @@ pub fn init(context: &mut Context) { SyntaxError, EvalError, UriError, + AggregateError, Reflect }; diff --git a/boa_engine/src/context.rs b/boa_engine/src/context.rs index 042a11972c4..b0773b05948 100644 --- a/boa_engine/src/context.rs +++ b/boa_engine/src/context.rs @@ -85,6 +85,7 @@ pub struct StandardObjects { syntax_error: StandardConstructor, eval_error: StandardConstructor, uri_error: StandardConstructor, + aggregate_error: StandardConstructor, map: StandardConstructor, set: StandardConstructor, typed_array: StandardConstructor, @@ -134,6 +135,7 @@ impl Default for StandardObjects { syntax_error: StandardConstructor::default(), eval_error: StandardConstructor::default(), uri_error: StandardConstructor::default(), + aggregate_error: StandardConstructor::default(), map: StandardConstructor::default(), set: StandardConstructor::default(), typed_array: StandardConstructor::default(), @@ -250,6 +252,11 @@ impl StandardObjects { &self.uri_error } + #[inline] + pub fn aggregate_error_object(&self) -> &StandardConstructor { + &self.aggregate_error + } + #[inline] pub fn map_object(&self) -> &StandardConstructor { &self.map