diff --git a/Cargo.lock b/Cargo.lock index 35b1b82dc30..98f2c6dfdf1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,6 +106,7 @@ dependencies = [ "ryu-js", "serde", "serde_json", + "tap", "unicode-normalization", ] @@ -1435,6 +1436,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "textwrap" version = "0.11.0" diff --git a/boa_engine/Cargo.toml b/boa_engine/Cargo.toml index 5acfcf8da92..3a3b4779ffa 100644 --- a/boa_engine/Cargo.toml +++ b/boa_engine/Cargo.toml @@ -57,7 +57,7 @@ fast-float = "0.2.0" unicode-normalization = "0.1.19" dyn-clone = "1.0.4" once_cell = "1.9.0" - +tap = "1.0.1" [dev-dependencies] criterion = "0.3.5" float-cmp = "0.9.0" diff --git a/boa_engine/src/builtins/array/array_iterator.rs b/boa_engine/src/builtins/array/array_iterator.rs index e8621c22a27..2820337b1e9 100644 --- a/boa_engine/src/builtins/array/array_iterator.rs +++ b/boa_engine/src/builtins/array/array_iterator.rs @@ -48,7 +48,11 @@ impl ArrayIterator { context: &Context, ) -> JsValue { let array_iterator = JsObject::from_proto_and_data( - context.iterator_prototypes().array_iterator(), + context + .intrinsics() + .objects() + .iterator_prototypes() + .array_iterator(), ObjectData::array_iterator(Self::new(array, kind)), ); array_iterator.into() diff --git a/boa_engine/src/builtins/array/mod.rs b/boa_engine/src/builtins/array/mod.rs index 844cefadda7..0e5eeeda137 100644 --- a/boa_engine/src/builtins/array/mod.rs +++ b/boa_engine/src/builtins/array/mod.rs @@ -14,13 +14,14 @@ pub mod array_iterator; mod tests; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; use super::JsArgs; use crate::{ builtins::array::array_iterator::ArrayIterator, builtins::BuiltIn, builtins::Number, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, FunctionBuilder, JsObject, ObjectData, @@ -39,11 +40,7 @@ pub(crate) struct Array; impl BuiltIn for Array { const NAME: &'static str = "Array"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let symbol_iterator = WellKnownSymbols::iterator(); @@ -55,10 +52,10 @@ impl BuiltIn for Array { let values_function = Self::values_intrinsic(context); - let array = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().array_object().clone(), + context.intrinsics().standard_constructors().array().clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -118,9 +115,9 @@ impl BuiltIn for Array { // Static Methods .static_method(Self::is_array, "isArray", 1) .static_method(Self::of, "of", 0) - .build(); - - array.into() + .build() + .conv::() + .pipe(Some) } } @@ -135,7 +132,7 @@ impl Array { // If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget. // 2. Let proto be ? GetPrototypeFromConstructor(newTarget, "%Array.prototype%"). let prototype = - get_prototype_from_constructor(new_target, StandardObjects::array_object, context)?; + get_prototype_from_constructor(new_target, StandardConstructors::array, context)?; // 3. Let numberOfArgs be the number of elements in values. let number_of_args = args.len(); @@ -226,7 +223,11 @@ impl Array { // 5. Set A.[[DefineOwnProperty]] as specified in 10.4.2.1. let prototype = match prototype { Some(prototype) => prototype, - None => context.standard_objects().array_object().prototype(), + None => context + .intrinsics() + .standard_constructors() + .array() + .prototype(), }; let array = JsObject::from_proto_and_data(prototype, ObjectData::array()); diff --git a/boa_engine/src/builtins/array_buffer/mod.rs b/boa_engine/src/builtins/array_buffer/mod.rs index b485fd78f6f..89f9ec5e23d 100644 --- a/boa_engine/src/builtins/array_buffer/mod.rs +++ b/boa_engine/src/builtins/array_buffer/mod.rs @@ -3,7 +3,7 @@ mod tests; use crate::{ builtins::{typed_array::TypedArrayKind, BuiltIn, JsArgs}, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, FunctionBuilder, JsObject, ObjectData, @@ -16,6 +16,7 @@ use crate::{ use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; use num_traits::{Signed, ToPrimitive}; +use tap::{Conv, Pipe}; #[derive(Debug, Clone, Trace, Finalize)] pub struct ArrayBuffer { @@ -33,11 +34,7 @@ impl ArrayBuffer { impl BuiltIn for ArrayBuffer { const NAME: &'static str = "ArrayBuffer"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let get_species = FunctionBuilder::native(context, Self::get_species) @@ -45,10 +42,14 @@ impl BuiltIn for ArrayBuffer { .constructor(false) .build(); - ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().array_buffer_object().clone(), + context + .intrinsics() + .standard_constructors() + .array_buffer() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -67,7 +68,8 @@ impl BuiltIn for ArrayBuffer { Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .build() - .into() + .conv::() + .pipe(Some) } } @@ -230,7 +232,7 @@ impl ArrayBuffer { let new_len = std::cmp::max(r#final - first, 0) as usize; // 15. Let ctor be ? SpeciesConstructor(O, %ArrayBuffer%). - let ctor = obj.species_constructor(StandardObjects::array_buffer_object, context)?; + let ctor = obj.species_constructor(StandardConstructors::array_buffer, context)?; // 16. Let new be ? Construct(ctor, « 𝔽(newLen) »). let new = ctor.construct(&[new_len.into()], &ctor.clone().into(), context)?; @@ -310,7 +312,7 @@ impl ArrayBuffer { // 1. Let obj be ? OrdinaryCreateFromConstructor(constructor, "%ArrayBuffer.prototype%", « [[ArrayBufferData]], [[ArrayBufferByteLength]], [[ArrayBufferDetachKey]] »). let prototype = get_prototype_from_constructor( constructor, - StandardObjects::array_buffer_object, + StandardConstructors::array_buffer, context, )?; let obj = context.construct_object(); diff --git a/boa_engine/src/builtins/bigint/mod.rs b/boa_engine/src/builtins/bigint/mod.rs index 86a074b86fd..3f034652e2c 100644 --- a/boa_engine/src/builtins/bigint/mod.rs +++ b/boa_engine/src/builtins/bigint/mod.rs @@ -22,6 +22,7 @@ use crate::{ }; use boa_profiler::Profiler; use num_bigint::ToBigInt; +use tap::{Conv, Pipe}; #[cfg(test)] mod tests; @@ -33,19 +34,19 @@ pub struct BigInt; impl BuiltIn for BigInt { const NAME: &'static str = "BigInt"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let to_string_tag = WellKnownSymbols::to_string_tag(); - let bigint_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().bigint_object().clone(), + context + .intrinsics() + .standard_constructors() + .bigint_object() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -60,9 +61,9 @@ impl BuiltIn for BigInt { Self::NAME, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .build(); - - bigint_object.into() + .build() + .conv::() + .pipe(Some) } } diff --git a/boa_engine/src/builtins/boolean/mod.rs b/boa_engine/src/builtins/boolean/mod.rs index b14d46d4223..12bf066ac4f 100644 --- a/boa_engine/src/builtins/boolean/mod.rs +++ b/boa_engine/src/builtins/boolean/mod.rs @@ -14,14 +14,14 @@ mod tests; use crate::{ builtins::BuiltIn, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData, }, - property::Attribute, Context, JsResult, JsValue, }; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; /// Boolean implementation. #[derive(Debug, Clone, Copy)] @@ -31,25 +31,25 @@ impl BuiltIn for Boolean { /// The name of the object. const NAME: &'static str = "Boolean"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); - let boolean_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().boolean_object().clone(), + context + .intrinsics() + .standard_constructors() + .boolean() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) .method(Self::to_string, "toString", 0) .method(Self::value_of, "valueOf", 0) - .build(); - - boolean_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -71,7 +71,7 @@ impl Boolean { return Ok(JsValue::new(data)); } let prototype = - get_prototype_from_constructor(new_target, StandardObjects::boolean_object, context)?; + get_prototype_from_constructor(new_target, StandardConstructors::boolean, context)?; let boolean = JsObject::from_proto_and_data(prototype, ObjectData::boolean(data)); Ok(boolean.into()) diff --git a/boa_engine/src/builtins/console/mod.rs b/boa_engine/src/builtins/console/mod.rs index ed9b24a83f9..2aef07cb3e2 100644 --- a/boa_engine/src/builtins/console/mod.rs +++ b/boa_engine/src/builtins/console/mod.rs @@ -19,13 +19,13 @@ mod tests; use crate::{ builtins::{BuiltIn, JsArgs}, object::ObjectInitializer, - property::Attribute, value::{display::display_obj, JsValue, Numeric}, Context, JsResult, JsString, }; use boa_profiler::Profiler; use rustc_hash::FxHashMap; use std::time::SystemTime; +use tap::{Conv, Pipe}; /// This represents the different types of log messages. #[derive(Debug)] @@ -133,13 +133,9 @@ pub(crate) struct Console { impl BuiltIn for Console { const NAME: &'static str = "console"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); - let console = ObjectInitializer::new(context) + ObjectInitializer::new(context) .function(Self::assert, "assert", 0) .function(Self::clear, "clear", 0) .function(Self::debug, "debug", 0) @@ -159,9 +155,9 @@ impl BuiltIn for Console { .function(Self::time_end, "timeEnd", 0) .function(Self::dir, "dir", 0) .function(Self::dir, "dirxml", 0) - .build(); - - console.into() + .build() + .conv::() + .pipe(Some) } } diff --git a/boa_engine/src/builtins/dataview/mod.rs b/boa_engine/src/builtins/dataview/mod.rs index 6e587feb287..70b6d55875c 100644 --- a/boa_engine/src/builtins/dataview/mod.rs +++ b/boa_engine/src/builtins/dataview/mod.rs @@ -1,6 +1,6 @@ use crate::{ builtins::{array_buffer::SharedMemoryOrder, typed_array::TypedArrayKind, BuiltIn, JsArgs}, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, FunctionBuilder, JsObject, ObjectData, @@ -11,6 +11,7 @@ use crate::{ Context, JsResult, }; use boa_gc::{Finalize, Trace}; +use tap::{Conv, Pipe}; #[derive(Debug, Clone, Trace, Finalize)] pub struct DataView { @@ -22,11 +23,7 @@ pub struct DataView { impl BuiltIn for DataView { const NAME: &'static str = "DataView"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let flag_attributes = Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE; let get_buffer = FunctionBuilder::native(context, Self::get_buffer) @@ -41,10 +38,14 @@ impl BuiltIn for DataView { .name("get byteOffset") .build(); - let dataview_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().data_view_object().clone(), + context + .intrinsics() + .standard_constructors() + .data_view() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -76,9 +77,9 @@ impl BuiltIn for DataView { Self::NAME, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .build(); - - dataview_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -151,7 +152,7 @@ impl DataView { // 9. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%DataView.prototype%", « [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]] »). let prototype = - get_prototype_from_constructor(new_target, StandardObjects::data_view_object, context)?; + get_prototype_from_constructor(new_target, StandardConstructors::data_view, context)?; // 10. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. if buffer_obj diff --git a/boa_engine/src/builtins/date/mod.rs b/boa_engine/src/builtins/date/mod.rs index 590a3d33200..9460229aa0f 100644 --- a/boa_engine/src/builtins/date/mod.rs +++ b/boa_engine/src/builtins/date/mod.rs @@ -4,11 +4,10 @@ mod tests; use super::JsArgs; use crate::{ builtins::BuiltIn, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData, }, - property::Attribute, symbol::WellKnownSymbols, value::{JsValue, PreferredType}, Context, JsResult, JsString, @@ -17,6 +16,7 @@ use boa_gc::{unsafe_empty_trace, Finalize, Trace}; use boa_profiler::Profiler; use chrono::{prelude::*, Duration, LocalResult}; use std::fmt::Display; +use tap::{Conv, Pipe}; /// The number of nanoseconds in a millisecond. const NANOS_PER_MS: i64 = 1_000_000; @@ -88,14 +88,10 @@ impl Default for Date { impl BuiltIn for Date { const NAME: &'static str = "Date"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); - let date_object = ConstructorBuilder::new(context, Self::constructor) + ConstructorBuilder::new(context, Self::constructor) .name(Self::NAME) .length(Self::LENGTH) .method(getter_method!(get_date), "getDate", 0) @@ -154,9 +150,9 @@ impl BuiltIn for Date { .static_method(Self::now, "now", 0) .static_method(Self::parse, "parse", 1) .static_method(Self::utc, "UTC", 7) - .build(); - - date_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -340,11 +336,8 @@ impl Date { if new_target.is_undefined() { Ok(Self::make_date_string()) } else { - let prototype = get_prototype_from_constructor( - new_target, - StandardObjects::object_object, - context, - )?; + let prototype = + get_prototype_from_constructor(new_target, StandardConstructors::object, context)?; Ok(if args.is_empty() { Self::make_date_now(prototype) } else if args.len() == 1 { diff --git a/boa_engine/src/builtins/error/eval.rs b/boa_engine/src/builtins/error/eval.rs index 1e68003588b..d7c176afdb3 100644 --- a/boa_engine/src/builtins/error/eval.rs +++ b/boa_engine/src/builtins/error/eval.rs @@ -13,7 +13,7 @@ use crate::{ builtins::{BuiltIn, JsArgs}, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData, }, @@ -21,6 +21,7 @@ use crate::{ Context, JsResult, JsValue, }; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; use super::Error; @@ -31,21 +32,29 @@ pub(crate) struct EvalError; impl BuiltIn for EvalError { const NAME: &'static str = "EvalError"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { 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 error_constructor = context + .intrinsics() + .standard_constructors() + .error() + .constructor(); + let error_prototype = context + .intrinsics() + .standard_constructors() + .error() + .prototype(); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; - let eval_error_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().eval_error_object().clone(), + context + .intrinsics() + .standard_constructors() + .eval_error() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -53,9 +62,9 @@ impl BuiltIn for EvalError { .custom_prototype(error_constructor) .property("name", Self::NAME, attribute) .property("message", "", attribute) - .build(); - - eval_error_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -71,11 +80,8 @@ impl EvalError { ) -> JsResult { // 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget. // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%NativeError.prototype%", « [[ErrorData]] »). - let prototype = get_prototype_from_constructor( - new_target, - StandardObjects::eval_error_object, - context, - )?; + let prototype = + get_prototype_from_constructor(new_target, StandardConstructors::eval_error, context)?; let o = JsObject::from_proto_and_data(prototype, ObjectData::error()); // 3. If message is not undefined, then diff --git a/boa_engine/src/builtins/error/mod.rs b/boa_engine/src/builtins/error/mod.rs index eb9a79f2676..6fe4d648b4e 100644 --- a/boa_engine/src/builtins/error/mod.rs +++ b/boa_engine/src/builtins/error/mod.rs @@ -12,7 +12,7 @@ use crate::{ builtins::BuiltIn, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData, }, @@ -20,6 +20,7 @@ use crate::{ Context, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; pub(crate) mod eval; pub(crate) mod range; @@ -47,27 +48,23 @@ pub(crate) struct Error; impl BuiltIn for Error { const NAME: &'static str = "Error"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; - let error_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().error_object().clone(), + context.intrinsics().standard_constructors().error().clone(), ) .name(Self::NAME) .length(Self::LENGTH) .property("name", Self::NAME, attribute) .property("message", "", attribute) .method(Self::to_string, "toString", 0) - .build(); - - error_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -103,11 +100,11 @@ impl Error { args: &[JsValue], context: &mut Context, ) -> JsResult { - // 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget. + // 1. If NewTarget is undefined, let newTarget be the active functionerrore let newTarget be NewTarget. // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%Error.prototype%", « [[ErrorData]] »). let prototype = - get_prototype_from_constructor(new_target, StandardObjects::error_object, context)?; + get_prototype_from_constructor(new_target, StandardConstructors::error, context)?; let o = JsObject::from_proto_and_data(prototype, ObjectData::error()); // 3. If message is not undefined, then diff --git a/boa_engine/src/builtins/error/range.rs b/boa_engine/src/builtins/error/range.rs index bb6e20c0505..8c9110937db 100644 --- a/boa_engine/src/builtins/error/range.rs +++ b/boa_engine/src/builtins/error/range.rs @@ -11,7 +11,7 @@ use crate::{ builtins::{BuiltIn, JsArgs}, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData, }, @@ -19,6 +19,7 @@ use crate::{ Context, JsResult, JsValue, }; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; use super::Error; @@ -29,21 +30,29 @@ pub(crate) struct RangeError; impl BuiltIn for RangeError { const NAME: &'static str = "RangeError"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { 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 error_constructor = context + .intrinsics() + .standard_constructors() + .error() + .constructor(); + let error_prototype = context + .intrinsics() + .standard_constructors() + .error() + .prototype(); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; - let range_error_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().range_error_object().clone(), + context + .intrinsics() + .standard_constructors() + .range_error() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -51,9 +60,9 @@ impl BuiltIn for RangeError { .custom_prototype(error_constructor) .property("name", Self::NAME, attribute) .property("message", "", attribute) - .build(); - - range_error_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -69,11 +78,8 @@ impl RangeError { ) -> JsResult { // 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget. // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%NativeError.prototype%", « [[ErrorData]] »). - let prototype = get_prototype_from_constructor( - new_target, - StandardObjects::range_error_object, - context, - )?; + let prototype = + get_prototype_from_constructor(new_target, StandardConstructors::range_error, context)?; let o = JsObject::from_proto_and_data(prototype, ObjectData::error()); // 3. If message is not undefined, then diff --git a/boa_engine/src/builtins/error/reference.rs b/boa_engine/src/builtins/error/reference.rs index 7052a867b32..a346c555d27 100644 --- a/boa_engine/src/builtins/error/reference.rs +++ b/boa_engine/src/builtins/error/reference.rs @@ -11,7 +11,7 @@ use crate::{ builtins::{BuiltIn, JsArgs}, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData, }, @@ -19,6 +19,7 @@ use crate::{ Context, JsResult, JsValue, }; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; use super::Error; @@ -28,21 +29,29 @@ pub(crate) struct ReferenceError; impl BuiltIn for ReferenceError { const NAME: &'static str = "ReferenceError"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { 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 error_constructor = context + .intrinsics() + .standard_constructors() + .error() + .constructor(); + let error_prototype = context + .intrinsics() + .standard_constructors() + .error() + .prototype(); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; - let reference_error_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().reference_error_object().clone(), + context + .intrinsics() + .standard_constructors() + .reference_error() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -50,9 +59,9 @@ impl BuiltIn for ReferenceError { .custom_prototype(error_constructor) .property("name", Self::NAME, attribute) .property("message", "", attribute) - .build(); - - reference_error_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -70,7 +79,7 @@ impl ReferenceError { // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%NativeError.prototype%", « [[ErrorData]] »). let prototype = get_prototype_from_constructor( new_target, - StandardObjects::reference_error_object, + StandardConstructors::reference_error, context, )?; let o = JsObject::from_proto_and_data(prototype, ObjectData::error()); diff --git a/boa_engine/src/builtins/error/syntax.rs b/boa_engine/src/builtins/error/syntax.rs index f8f6436e821..e127d42be72 100644 --- a/boa_engine/src/builtins/error/syntax.rs +++ b/boa_engine/src/builtins/error/syntax.rs @@ -13,7 +13,7 @@ use crate::{ builtins::{BuiltIn, JsArgs}, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData, }, @@ -21,6 +21,7 @@ use crate::{ Context, JsResult, JsValue, }; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; use super::Error; @@ -31,21 +32,29 @@ pub(crate) struct SyntaxError; impl BuiltIn for SyntaxError { const NAME: &'static str = "SyntaxError"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { 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 error_constructor = context + .intrinsics() + .standard_constructors() + .error() + .constructor(); + let error_prototype = context + .intrinsics() + .standard_constructors() + .error() + .prototype(); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; - let syntax_error_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().syntax_error_object().clone(), + context + .intrinsics() + .standard_constructors() + .syntax_error() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -53,9 +62,9 @@ impl BuiltIn for SyntaxError { .custom_prototype(error_constructor) .property("name", Self::NAME, attribute) .property("message", "", attribute) - .build(); - - syntax_error_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -73,7 +82,7 @@ impl SyntaxError { // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%NativeError.prototype%", « [[ErrorData]] »). let prototype = get_prototype_from_constructor( new_target, - StandardObjects::syntax_error_object, + StandardConstructors::syntax_error, context, )?; let o = JsObject::from_proto_and_data(prototype, ObjectData::error()); diff --git a/boa_engine/src/builtins/error/type.rs b/boa_engine/src/builtins/error/type.rs index ec519017db0..aaa30e931d5 100644 --- a/boa_engine/src/builtins/error/type.rs +++ b/boa_engine/src/builtins/error/type.rs @@ -16,15 +16,16 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError use crate::{ - builtins::{BuiltIn, JsArgs}, - context::StandardObjects, + builtins::{function::Function, BuiltIn, JsArgs}, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData, }, - property::Attribute, + property::{Attribute, PropertyDescriptor}, Context, JsResult, JsValue, }; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; use super::Error; @@ -35,21 +36,29 @@ pub(crate) struct TypeError; impl BuiltIn for TypeError { const NAME: &'static str = "TypeError"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { 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 error_constructor = context + .intrinsics() + .standard_constructors() + .error() + .constructor(); + let error_prototype = context + .intrinsics() + .standard_constructors() + .error() + .prototype(); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; - let type_error_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().type_error_object().clone(), + context + .intrinsics() + .standard_constructors() + .type_error() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -57,9 +66,9 @@ impl BuiltIn for TypeError { .custom_prototype(error_constructor) .property("name", Self::NAME, attribute) .property("message", "", attribute) - .build(); - - type_error_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -75,11 +84,8 @@ impl TypeError { ) -> JsResult { // 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget. // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%NativeError.prototype%", « [[ErrorData]] »). - let prototype = get_prototype_from_constructor( - new_target, - StandardObjects::type_error_object, - context, - )?; + let prototype = + get_prototype_from_constructor(new_target, StandardConstructors::type_error, context)?; let o = JsObject::from_proto_and_data(prototype, ObjectData::error()); // 3. If message is not undefined, then @@ -99,3 +105,30 @@ impl TypeError { Ok(o.into()) } } + +pub(crate) fn create_throw_type_error(context: &mut Context) -> JsObject { + fn throw_type_error(_: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { + context.throw_type_error("invalid type") + } + + let function = JsObject::from_proto_and_data( + context + .intrinsics() + .standard_constructors() + .function() + .prototype(), + ObjectData::function(Function::Native { + function: throw_type_error, + constructor: false, + }), + ); + + let property = PropertyDescriptor::builder() + .writable(false) + .enumerable(false) + .configurable(false); + function.insert_property("name", property.clone().value("ThrowTypeError")); + function.insert_property("length", property.value(0)); + + function +} diff --git a/boa_engine/src/builtins/error/uri.rs b/boa_engine/src/builtins/error/uri.rs index 9b13adebedc..cb47dfe877f 100644 --- a/boa_engine/src/builtins/error/uri.rs +++ b/boa_engine/src/builtins/error/uri.rs @@ -12,7 +12,7 @@ use crate::{ builtins::{BuiltIn, JsArgs}, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData, }, @@ -20,6 +20,7 @@ use crate::{ Context, JsResult, JsValue, }; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; use super::Error; @@ -30,21 +31,29 @@ pub(crate) struct UriError; impl BuiltIn for UriError { const NAME: &'static str = "URIError"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { 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 error_constructor = context + .intrinsics() + .standard_constructors() + .error() + .constructor(); + let error_prototype = context + .intrinsics() + .standard_constructors() + .error() + .prototype(); let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; - let uri_error_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().uri_error_object().clone(), + context + .intrinsics() + .standard_constructors() + .uri_error() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -52,9 +61,9 @@ impl BuiltIn for UriError { .custom_prototype(error_constructor) .property("name", Self::NAME, attribute) .property("message", "", attribute) - .build(); - - uri_error_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -71,7 +80,7 @@ impl UriError { // 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget. // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%NativeError.prototype%", « [[ErrorData]] »). let prototype = - get_prototype_from_constructor(new_target, StandardObjects::uri_error_object, context)?; + get_prototype_from_constructor(new_target, StandardConstructors::uri_error, context)?; let o = JsObject::from_proto_and_data(prototype, ObjectData::error()); // 3. If message is not undefined, then diff --git a/boa_engine/src/builtins/function/arguments.rs b/boa_engine/src/builtins/function/arguments.rs index b96cdc70a46..274a741436f 100644 --- a/boa_engine/src/builtins/function/arguments.rs +++ b/boa_engine/src/builtins/function/arguments.rs @@ -122,7 +122,7 @@ impl Arguments { ) .expect("Defining new own properties for a new ordinary object cannot fail"); - let throw_type_error = context.intrinsics().throw_type_error(); + let throw_type_error = context.intrinsics().objects().throw_type_error(); // 8. Perform ! DefinePropertyOrThrow(obj, "callee", PropertyDescriptor { // [[Get]]: %ThrowTypeError%, [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, @@ -224,7 +224,11 @@ impl Arguments { // 11. Set obj.[[ParameterMap]] to map. let obj = JsObject::from_proto_and_data( - context.standard_objects().object_object().prototype(), + context + .intrinsics() + .standard_constructors() + .object() + .prototype(), ObjectData::arguments(Self::Mapped(map)), ); diff --git a/boa_engine/src/builtins/function/mod.rs b/boa_engine/src/builtins/function/mod.rs index c4c35c24948..bec7baeeddc 100644 --- a/boa_engine/src/builtins/function/mod.rs +++ b/boa_engine/src/builtins/function/mod.rs @@ -13,7 +13,7 @@ use crate::{ builtins::{BuiltIn, JsArgs}, - context::StandardObjects, + context::intrinsics::StandardConstructors, environments::DeclarativeEnvironmentStack, object::{ internal_methods::get_prototype_from_constructor, JsObject, NativeObject, Object, @@ -34,6 +34,7 @@ use std::{ fmt, ops::{Deref, DerefMut}, }; +use tap::{Conv, Pipe}; pub(crate) mod arguments; #[cfg(test)] @@ -233,7 +234,11 @@ pub(crate) fn make_builtin_fn( let _timer = Profiler::global().start_event(&format!("make_builtin_fn: {name}"), "init"); let function = JsObject::from_proto_and_data( - interpreter.standard_objects().function_object().prototype(), + interpreter + .intrinsics() + .standard_constructors() + .function() + .prototype(), ObjectData::function(Function::Native { function, constructor: false, @@ -268,7 +273,7 @@ impl BuiltInFunctionObject { context: &mut Context, ) -> JsResult { let prototype = - get_prototype_from_constructor(new_target, StandardObjects::function_object, context)?; + get_prototype_from_constructor(new_target, StandardConstructors::function, context)?; let this = JsObject::from_proto_and_data( prototype, @@ -492,14 +497,14 @@ impl BuiltInFunctionObject { impl BuiltIn for BuiltInFunctionObject { const NAME: &'static str = "Function"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event("function", "init"); - let function_prototype = context.standard_objects().function_object().prototype(); + let function_prototype = context + .intrinsics() + .standard_constructors() + .function() + .prototype(); FunctionBuilder::native(context, Self::prototype) .name("") .length(0) @@ -514,10 +519,14 @@ impl BuiltIn for BuiltInFunctionObject { .constructor(false) .build(); - let function_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().function_object().clone(), + context + .intrinsics() + .standard_constructors() + .function() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -526,9 +535,9 @@ impl BuiltIn for BuiltInFunctionObject { .method(Self::call, "call", 1) .method(Self::to_string, "toString", 0) .property(symbol_has_instance, has_instance, Attribute::default()) - .build(); - - function_object.into() + .build() + .conv::() + .pipe(Some) } } diff --git a/boa_engine/src/builtins/generator/mod.rs b/boa_engine/src/builtins/generator/mod.rs index 9801bc231f9..c160b79339c 100644 --- a/boa_engine/src/builtins/generator/mod.rs +++ b/boa_engine/src/builtins/generator/mod.rs @@ -59,20 +59,29 @@ impl BuiltIn for Generator { const ATTRIBUTE: Attribute = Attribute::NON_ENUMERABLE.union(Attribute::CONFIGURABLE); - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); - let iterator_prototype = context.iterator_prototypes().iterator_prototype(); + let iterator_prototype = context + .intrinsics() + .objects() + .iterator_prototypes() + .iterator_prototype(); let generator_function_prototype = context - .standard_objects() - .generator_function_object() + .intrinsics() + .standard_constructors() + .generator_function() .prototype(); - let obj = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().generator_object().clone(), + context + .intrinsics() + .standard_constructors() + .generator() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -88,8 +97,9 @@ impl BuiltIn for Generator { .build(); context - .standard_objects() - .generator_object() + .intrinsics() + .standard_constructors() + .generator() .prototype .insert_property( "constructor", @@ -100,7 +110,7 @@ impl BuiltIn for Generator { .configurable(true), ); - obj.into() + None } } @@ -113,7 +123,11 @@ impl Generator { _: &[JsValue], context: &mut Context, ) -> JsResult { - let prototype = context.standard_objects().generator_object().prototype(); + let prototype = context + .intrinsics() + .standard_constructors() + .generator() + .prototype(); let this = JsObject::from_proto_and_data( prototype, diff --git a/boa_engine/src/builtins/generator_function/mod.rs b/boa_engine/src/builtins/generator_function/mod.rs index d3dcfdcead8..1f7e38815c5 100644 --- a/boa_engine/src/builtins/generator_function/mod.rs +++ b/boa_engine/src/builtins/generator_function/mod.rs @@ -12,7 +12,7 @@ use crate::{ builtins::{function::Function, BuiltIn}, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::{Attribute, PropertyDescriptor}, symbol::WellKnownSymbols, @@ -30,20 +30,26 @@ impl BuiltIn for GeneratorFunction { const ATTRIBUTE: Attribute = Attribute::NON_ENUMERABLE.union(Attribute::WRITABLE); - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let prototype = &context - .standard_objects() - .generator_function_object() + .intrinsics() + .standard_constructors() + .generator_function() .prototype; let constructor = &context - .standard_objects() - .generator_function_object() + .intrinsics() + .standard_constructors() + .generator_function() .constructor; constructor.set_prototype(Some( - context.standard_objects().function_object().constructor(), + context + .intrinsics() + .standard_constructors() + .function() + .constructor(), )); let property = PropertyDescriptor::builder() .value(1) @@ -60,8 +66,9 @@ impl BuiltIn for GeneratorFunction { let property = PropertyDescriptor::builder() .value( context - .standard_objects() - .generator_function_object() + .intrinsics() + .standard_constructors() + .generator_function() .prototype(), ) .writable(false) @@ -74,13 +81,18 @@ impl BuiltIn for GeneratorFunction { }); prototype.set_prototype(Some( - context.standard_objects().function_object().prototype(), + context + .intrinsics() + .standard_constructors() + .function() + .prototype(), )); let property = PropertyDescriptor::builder() .value( context - .standard_objects() - .generator_function_object() + .intrinsics() + .standard_constructors() + .generator_function() .constructor(), ) .writable(false) @@ -88,7 +100,13 @@ impl BuiltIn for GeneratorFunction { .configurable(true); prototype.borrow_mut().insert("constructor", property); let property = PropertyDescriptor::builder() - .value(context.standard_objects().generator_object().prototype()) + .value( + context + .intrinsics() + .standard_constructors() + .generator() + .prototype(), + ) .writable(false) .enumerable(false) .configurable(true); @@ -102,7 +120,7 @@ impl BuiltIn for GeneratorFunction { .borrow_mut() .insert(WellKnownSymbols::to_string_tag(), property); - JsValue::Null + None } } @@ -114,7 +132,7 @@ impl GeneratorFunction { ) -> JsResult { let prototype = get_prototype_from_constructor( new_target, - StandardObjects::generator_function_object, + StandardConstructors::generator_function, context, )?; diff --git a/boa_engine/src/builtins/global_this/mod.rs b/boa_engine/src/builtins/global_this/mod.rs index 451b5fa09a8..ac6f6f2a687 100644 --- a/boa_engine/src/builtins/global_this/mod.rs +++ b/boa_engine/src/builtins/global_this/mod.rs @@ -10,7 +10,7 @@ //! [spec]: https://tc39.es/ecma262/#sec-globalthis //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis -use crate::{builtins::BuiltIn, property::Attribute, Context, JsValue}; +use crate::{builtins::BuiltIn, Context, JsValue}; use boa_profiler::Profiler; #[cfg(test)] @@ -22,13 +22,9 @@ pub(crate) struct GlobalThis; impl BuiltIn for GlobalThis { const NAME: &'static str = "globalThis"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); - context.global_object().clone().into() + Some(context.global_object().clone().into()) } } diff --git a/boa_engine/src/builtins/infinity/mod.rs b/boa_engine/src/builtins/infinity/mod.rs index 96748a252fb..2800be3cfc2 100644 --- a/boa_engine/src/builtins/infinity/mod.rs +++ b/boa_engine/src/builtins/infinity/mod.rs @@ -26,9 +26,9 @@ impl BuiltIn for Infinity { .union(Attribute::NON_ENUMERABLE) .union(Attribute::PERMANENT); - fn init(_: &mut Context) -> JsValue { + fn init(_: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); - f64::INFINITY.into() + Some(f64::INFINITY.into()) } } diff --git a/boa_engine/src/builtins/intl/mod.rs b/boa_engine/src/builtins/intl/mod.rs index dcd3c2bb481..0410c755249 100644 --- a/boa_engine/src/builtins/intl/mod.rs +++ b/boa_engine/src/builtins/intl/mod.rs @@ -16,6 +16,7 @@ use crate::{ }; use boa_profiler::Profiler; use indexmap::IndexSet; +use tap::{Conv, Pipe}; /// JavaScript `Intl` object. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -24,24 +25,20 @@ pub(crate) struct Intl; impl BuiltIn for Intl { const NAME: &'static str = "Intl"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let string_tag = WellKnownSymbols::to_string_tag(); - let object = ObjectInitializer::new(context) + ObjectInitializer::new(context) .function(Self::get_canonical_locales, "getCanonicalLocales", 1) .property( string_tag, Self::NAME, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .build(); - - object.into() + .build() + .conv::() + .pipe(Some) } } diff --git a/boa_engine/src/builtins/intrinsics.rs b/boa_engine/src/builtins/intrinsics.rs deleted file mode 100644 index 5823f59e8a3..00000000000 --- a/boa_engine/src/builtins/intrinsics.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::{ - builtins::function::Function, - object::{JsObject, ObjectData}, - property::PropertyDescriptor, - Context, JsResult, JsValue, -}; - -#[derive(Debug, Default)] -pub struct IntrinsicObjects { - throw_type_error: JsObject, -} - -impl IntrinsicObjects { - pub fn init(context: &mut Context) -> Self { - Self { - throw_type_error: create_throw_type_error(context), - } - } - - pub fn throw_type_error(&self) -> JsObject { - self.throw_type_error.clone() - } -} - -fn create_throw_type_error(context: &mut Context) -> JsObject { - fn throw_type_error(_: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { - context.throw_type_error("invalid type") - } - - let function = JsObject::from_proto_and_data( - context.standard_objects().function_object().prototype(), - ObjectData::function(Function::Native { - function: throw_type_error, - constructor: false, - }), - ); - - let property = PropertyDescriptor::builder() - .writable(false) - .enumerable(false) - .configurable(false); - function.insert_property("name", property.clone().value("ThrowTypeError")); - function.insert_property("length", property.value(0)); - - function -} diff --git a/boa_engine/src/builtins/iterable/mod.rs b/boa_engine/src/builtins/iterable/mod.rs index f5371d77097..a5c773c6c70 100644 --- a/boa_engine/src/builtins/iterable/mod.rs +++ b/boa_engine/src/builtins/iterable/mod.rs @@ -12,12 +12,19 @@ use boa_profiler::Profiler; #[derive(Debug, Default)] pub struct IteratorPrototypes { + /// %IteratorPrototype% iterator_prototype: JsObject, + /// %MapIteratorPrototype% array_iterator: JsObject, + /// %SetIteratorPrototype% set_iterator: JsObject, + /// %StringIteratorPrototype% string_iterator: JsObject, + /// %RegExpStringIteratorPrototype% regexp_string_iterator: JsObject, + /// %MapIteratorPrototype% map_iterator: JsObject, + /// %ForInIteratorPrototype% for_in_iterator: JsObject, } diff --git a/boa_engine/src/builtins/json/mod.rs b/boa_engine/src/builtins/json/mod.rs index fc2596f980e..e51e10110cf 100644 --- a/boa_engine/src/builtins/json/mod.rs +++ b/boa_engine/src/builtins/json/mod.rs @@ -27,6 +27,7 @@ use crate::{ }; use boa_profiler::Profiler; use serde_json::{self, Value as JSONValue}; +use tap::{Conv, Pipe}; #[cfg(test)] mod tests; @@ -38,23 +39,19 @@ pub(crate) struct Json; impl BuiltIn for Json { const NAME: &'static str = "JSON"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let to_string_tag = WellKnownSymbols::to_string_tag(); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE; - let json_object = ObjectInitializer::new(context) + ObjectInitializer::new(context) .function(Self::parse, "parse", 2) .function(Self::stringify, "stringify", 3) .property(to_string_tag, Self::NAME, attribute) - .build(); - - json_object.into() + .build() + .conv::() + .pipe(Some) } } diff --git a/boa_engine/src/builtins/json/tests.rs b/boa_engine/src/builtins/json/tests.rs index be350aae4a9..4807d72e4e8 100644 --- a/boa_engine/src/builtins/json/tests.rs +++ b/boa_engine/src/builtins/json/tests.rs @@ -422,11 +422,17 @@ fn json_parse_sets_prototypes() { .prototype() .clone(); let global_object_prototype = context - .standard_objects() - .object_object() + .intrinsics() + .standard_constructors() + .object() + .prototype() + .into(); + let global_array_prototype = context + .intrinsics() + .standard_constructors() + .array() .prototype() .into(); - let global_array_prototype = context.standard_objects().array_object().prototype().into(); assert_eq!(object_prototype, global_object_prototype); assert_eq!(array_prototype, global_array_prototype); } diff --git a/boa_engine/src/builtins/map/map_iterator.rs b/boa_engine/src/builtins/map/map_iterator.rs index f84e565c4cc..7ed7c236c34 100644 --- a/boa_engine/src/builtins/map/map_iterator.rs +++ b/boa_engine/src/builtins/map/map_iterator.rs @@ -49,7 +49,11 @@ impl MapIterator { lock, }; let map_iterator = JsObject::from_proto_and_data( - context.iterator_prototypes().map_iterator(), + context + .intrinsics() + .objects() + .iterator_prototypes() + .map_iterator(), ObjectData::map_iterator(iter), ); return Ok(map_iterator.into()); diff --git a/boa_engine/src/builtins/map/mod.rs b/boa_engine/src/builtins/map/mod.rs index 06579579660..c862c8ae4bf 100644 --- a/boa_engine/src/builtins/map/mod.rs +++ b/boa_engine/src/builtins/map/mod.rs @@ -16,7 +16,7 @@ use self::{map_iterator::MapIterator, ordered_map::OrderedMap}; use super::JsArgs; use crate::{ builtins::BuiltIn, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, FunctionBuilder, JsObject, ObjectData, @@ -27,6 +27,7 @@ use crate::{ }; use boa_profiler::Profiler; use num_traits::Zero; +use tap::{Conv, Pipe}; pub mod map_iterator; pub mod ordered_map; @@ -39,11 +40,7 @@ pub(crate) struct Map(OrderedMap); impl BuiltIn for Map { const NAME: &'static str = "Map"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let get_species = FunctionBuilder::native(context, Self::get_species) @@ -63,10 +60,10 @@ impl BuiltIn for Map { .constructor(false) .build(); - let map_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().map_object().clone(), + context.intrinsics().standard_constructors().map().clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -100,9 +97,9 @@ impl BuiltIn for Map { .method(Self::set, "set", 2) .method(Self::values, "values", 0) .accessor("size", Some(get_size), None, Attribute::CONFIGURABLE) - .build(); - - map_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -133,7 +130,7 @@ impl Map { // 2. Let map be ? OrdinaryCreateFromConstructor(NewTarget, "%Map.prototype%", « [[MapData]] »). // 3. Set map.[[MapData]] to a new empty List. let prototype = - get_prototype_from_constructor(new_target, StandardObjects::map_object, context)?; + get_prototype_from_constructor(new_target, StandardConstructors::map, context)?; let map = JsObject::from_proto_and_data(prototype, ObjectData::map(OrderedMap::new())); // 4. If iterable is either undefined or null, return map. diff --git a/boa_engine/src/builtins/math/mod.rs b/boa_engine/src/builtins/math/mod.rs index aa516c3f917..f3b919cd752 100644 --- a/boa_engine/src/builtins/math/mod.rs +++ b/boa_engine/src/builtins/math/mod.rs @@ -17,6 +17,7 @@ use crate::{ Context, JsResult, JsValue, }; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; #[cfg(test)] mod tests; @@ -28,16 +29,12 @@ pub(crate) struct Math; impl BuiltIn for Math { const NAME: &'static str = "Math"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; let string_tag = WellKnownSymbols::to_string_tag(); - let object = ObjectInitializer::new(context) + ObjectInitializer::new(context) .property("E", std::f64::consts::E, attribute) .property("LN10", std::f64::consts::LN_10, attribute) .property("LN2", std::f64::consts::LN_2, attribute) @@ -86,9 +83,9 @@ impl BuiltIn for Math { Self::NAME, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .build(); - - object.into() + .build() + .conv::() + .pipe(Some) } } diff --git a/boa_engine/src/builtins/mod.rs b/boa_engine/src/builtins/mod.rs index 65795897ed4..8080db0b644 100644 --- a/boa_engine/src/builtins/mod.rs +++ b/boa_engine/src/builtins/mod.rs @@ -15,7 +15,6 @@ pub mod generator_function; pub mod global_this; pub mod infinity; pub mod intl; -pub mod intrinsics; pub mod iterable; pub mod json; pub mod map; @@ -68,6 +67,7 @@ pub(crate) use self::{ use crate::{ builtins::{ array_buffer::ArrayBuffer, generator::Generator, generator_function::GeneratorFunction, + typed_array::TypedArray, }, property::{Attribute, PropertyDescriptor}, Context, JsValue, @@ -88,28 +88,36 @@ pub(crate) trait BuiltIn { /// Property attribute flags of the built-in. /// Check [Attribute] for more information. - const ATTRIBUTE: Attribute; + const ATTRIBUTE: Attribute = Attribute::WRITABLE + .union(Attribute::NON_ENUMERABLE) + .union(Attribute::CONFIGURABLE); /// Initialization code for the built-in. /// This is where the methods, properties, static methods and the constructor /// of a built-in must be initialized to be accessible from Javascript. - fn init(context: &mut Context) -> JsValue; + /// + /// # Note + /// + /// A return value of `None` indicates that the value must not be added as + /// a global attribute for the global object. + fn init(context: &mut Context) -> Option; } /// Utility function that checks if a type implements `BuiltIn` before /// initializing it as a global built-in. #[inline] fn init_builtin(context: &mut Context) { - let value = B::init(context); - let property = PropertyDescriptor::builder() - .value(value) - .writable(B::ATTRIBUTE.writable()) - .enumerable(B::ATTRIBUTE.enumerable()) - .configurable(B::ATTRIBUTE.configurable()) - .build(); - context - .global_bindings_mut() - .insert(B::NAME.into(), property); + if let Some(value) = B::init(context) { + let property = PropertyDescriptor::builder() + .value(value) + .writable(B::ATTRIBUTE.writable()) + .enumerable(B::ATTRIBUTE.enumerable()) + .configurable(B::ATTRIBUTE.configurable()) + .build(); + context + .global_bindings_mut() + .insert(B::NAME.into(), property); + } } /// Initializes built-in objects and functions @@ -144,6 +152,7 @@ pub fn init(context: &mut Context) { Set, String, RegExp, + TypedArray, Int8Array, Uint8Array, Uint8ClampedArray, @@ -163,12 +172,11 @@ pub fn init(context: &mut Context) { SyntaxError, EvalError, UriError, - Reflect + Reflect, + Generator, + GeneratorFunction }; - Generator::init(context); - GeneratorFunction::init(context); - #[cfg(feature = "console")] init_builtin::(context); } diff --git a/boa_engine/src/builtins/nan/mod.rs b/boa_engine/src/builtins/nan/mod.rs index 6d05a3c5046..7c89361d73c 100644 --- a/boa_engine/src/builtins/nan/mod.rs +++ b/boa_engine/src/builtins/nan/mod.rs @@ -27,9 +27,9 @@ impl BuiltIn for NaN { .union(Attribute::NON_ENUMERABLE) .union(Attribute::PERMANENT); - fn init(_: &mut Context) -> JsValue { + fn init(_: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); - f64::NAN.into() + Some(f64::NAN.into()) } } diff --git a/boa_engine/src/builtins/number/mod.rs b/boa_engine/src/builtins/number/mod.rs index 1c84fc27e99..ed484059ff7 100644 --- a/boa_engine/src/builtins/number/mod.rs +++ b/boa_engine/src/builtins/number/mod.rs @@ -15,7 +15,7 @@ use crate::{ builtins::{string::is_trimmable_whitespace, BuiltIn, JsArgs}, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData, }, @@ -29,6 +29,7 @@ use num_traits::{float::FloatCore, Num}; mod conversions; pub(crate) use conversions::{f64_to_int32, f64_to_uint32}; +use tap::{Conv, Pipe}; #[cfg(test)] mod tests; @@ -42,18 +43,23 @@ pub(crate) struct Number; impl BuiltIn for Number { const NAME: &'static str = "Number"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); + context.register_global_builtin_function("parseInt", 2, Self::parse_int); + context.register_global_builtin_function("parseFloat", 1, Self::parse_float); + context.register_global_builtin_function("isFinite", 1, Self::global_is_finite); + context.register_global_builtin_function("isNaN", 1, Self::global_is_nan); + let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; - let number_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().number_object().clone(), + context + .intrinsics() + .standard_constructors() + .number() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -75,14 +81,9 @@ impl BuiltIn for Number { .static_method(Self::number_is_nan, "isNaN", 1) .static_method(Self::is_safe_integer, "isSafeInteger", 1) .static_method(Self::number_is_integer, "isInteger", 1) - .build(); - - context.register_global_builtin_function("parseInt", 2, Self::parse_int); - context.register_global_builtin_function("parseFloat", 1, Self::parse_float); - context.register_global_builtin_function("isFinite", 1, Self::global_is_finite); - context.register_global_builtin_function("isNaN", 1, Self::global_is_nan); - - number_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -150,7 +151,7 @@ impl Number { return Ok(JsValue::new(data)); } let prototype = - get_prototype_from_constructor(new_target, StandardObjects::number_object, context)?; + get_prototype_from_constructor(new_target, StandardConstructors::number, context)?; let this = JsObject::from_proto_and_data(prototype, ObjectData::number(data)); Ok(this.into()) } diff --git a/boa_engine/src/builtins/object/for_in_iterator.rs b/boa_engine/src/builtins/object/for_in_iterator.rs index 13a5a5f2ae2..612daa0b499 100644 --- a/boa_engine/src/builtins/object/for_in_iterator.rs +++ b/boa_engine/src/builtins/object/for_in_iterator.rs @@ -48,7 +48,11 @@ impl ForInIterator { /// [spec]: https://tc39.es/ecma262/#sec-createforiniterator pub(crate) fn create_for_in_iterator(object: JsValue, context: &Context) -> JsValue { let for_in_iterator = JsObject::from_proto_and_data( - context.iterator_prototypes().for_in_iterator(), + context + .intrinsics() + .objects() + .iterator_prototypes() + .for_in_iterator(), ObjectData::for_in_iterator(Self::new(object)), ); for_in_iterator.into() diff --git a/boa_engine/src/builtins/object/mod.rs b/boa_engine/src/builtins/object/mod.rs index 7a53b7913f0..f6ebb385c51 100644 --- a/boa_engine/src/builtins/object/mod.rs +++ b/boa_engine/src/builtins/object/mod.rs @@ -16,17 +16,18 @@ use super::Array; use crate::{ builtins::{map, BuiltIn, JsArgs}, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, FunctionBuilder, IntegrityLevel, JsObject, ObjectData, ObjectKind, }, - property::{Attribute, PropertyDescriptor, PropertyKey, PropertyNameKind}, + property::{PropertyDescriptor, PropertyKey, PropertyNameKind}, symbol::WellKnownSymbols, value::JsValue, Context, JsResult, JsString, }; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; pub mod for_in_iterator; #[cfg(test)] @@ -39,17 +40,17 @@ pub struct Object; impl BuiltIn for Object { const NAME: &'static str = "Object"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); - let object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().object_object().clone(), + context + .intrinsics() + .standard_constructors() + .object() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -90,9 +91,9 @@ impl BuiltIn for Object { .static_method(Self::get_own_property_symbols, "getOwnPropertySymbols", 1) .static_method(Self::has_own, "hasOwn", 2) .static_method(Self::from_entries, "fromEntries", 1) - .build(); - - object.into() + .build() + .conv::() + .pipe(Some) } } @@ -105,11 +106,8 @@ impl Object { context: &mut Context, ) -> JsResult { if !new_target.is_undefined() { - let prototype = get_prototype_from_constructor( - new_target, - StandardObjects::object_object, - context, - )?; + let prototype = + get_prototype_from_constructor(new_target, StandardConstructors::object, context)?; let object = JsObject::from_proto_and_data(prototype, ObjectData::ordinary()); return Ok(object.into()); } @@ -597,13 +595,16 @@ impl Object { }; let key = key.to_property_key(context)?; - let own_property = this + let own_prop = this .to_object(context)? .__get_own_property__(&key, context)?; - Ok(own_property.map_or(JsValue::new(false), |own_prop| { - JsValue::new(own_prop.enumerable()) - })) + own_prop + .as_ref() + .and_then(PropertyDescriptor::enumerable) + .unwrap_or_default() + .conv::() + .pipe(Ok) } /// `Object.assign( target, ...sources )` diff --git a/boa_engine/src/builtins/proxy/mod.rs b/boa_engine/src/builtins/proxy/mod.rs index 233e1a34de3..7b7ef462d43 100644 --- a/boa_engine/src/builtins/proxy/mod.rs +++ b/boa_engine/src/builtins/proxy/mod.rs @@ -13,11 +13,11 @@ use crate::{ builtins::{BuiltIn, JsArgs}, object::{ConstructorBuilder, FunctionBuilder, JsObject, ObjectData}, - property::Attribute, Context, JsResult, JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; /// Javascript `Proxy` object. #[derive(Debug, Clone, Trace, Finalize)] @@ -29,24 +29,21 @@ pub struct Proxy { impl BuiltIn for Proxy { const NAME: &'static str = "Proxy"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); - ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().proxy_object().clone(), + context.intrinsics().standard_constructors().proxy().clone(), ) .name(Self::NAME) .length(Self::LENGTH) - .constructor_has_prototype(false) + .has_prototype_property(false) .static_method(Self::revocable, "revocable", 2) .build() - .into() + .conv::() + .pipe(Some) } } @@ -114,7 +111,11 @@ impl Proxy { // 6. Set P.[[ProxyTarget]] to target. // 7. Set P.[[ProxyHandler]] to handler. let p = JsObject::from_proto_and_data( - context.standard_objects().object_object().prototype(), + context + .intrinsics() + .standard_constructors() + .object() + .prototype(), ObjectData::proxy( Self::new(target.clone(), handler.clone()), target.is_callable(), diff --git a/boa_engine/src/builtins/reflect/mod.rs b/boa_engine/src/builtins/reflect/mod.rs index 87cd25d043d..4dfe113bf6a 100644 --- a/boa_engine/src/builtins/reflect/mod.rs +++ b/boa_engine/src/builtins/reflect/mod.rs @@ -19,6 +19,7 @@ use crate::{ Context, JsResult, JsValue, }; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; #[cfg(test)] mod tests; @@ -30,16 +31,12 @@ pub(crate) struct Reflect; impl BuiltIn for Reflect { const NAME: &'static str = "Reflect"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let to_string_tag = WellKnownSymbols::to_string_tag(); - let object = ObjectInitializer::new(context) + ObjectInitializer::new(context) .function(Self::apply, "apply", 3) .function(Self::construct, "construct", 2) .function(Self::define_property, "defineProperty", 3) @@ -62,8 +59,9 @@ impl BuiltIn for Reflect { Self::NAME, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .build(); - object.into() + .build() + .conv::() + .pipe(Some) } } diff --git a/boa_engine/src/builtins/regexp/mod.rs b/boa_engine/src/builtins/regexp/mod.rs index fc58e5785b8..49c0332bfcb 100644 --- a/boa_engine/src/builtins/regexp/mod.rs +++ b/boa_engine/src/builtins/regexp/mod.rs @@ -15,7 +15,7 @@ use self::regexp_string_iterator::RegExpStringIterator; use super::JsArgs; use crate::{ builtins::{array::Array, string, BuiltIn}, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, FunctionBuilder, JsObject, ObjectData, @@ -30,6 +30,7 @@ use boa_gc::{unsafe_empty_trace, Finalize, Trace}; use boa_profiler::Profiler; use regress::Regex; use std::str::FromStr; +use tap::{Conv, Pipe}; #[cfg(test)] mod tests; @@ -52,11 +53,7 @@ unsafe impl Trace for RegExp { impl BuiltIn for RegExp { const NAME: &'static str = "RegExp"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let get_species = FunctionBuilder::native(context, Self::get_species) @@ -98,10 +95,14 @@ impl BuiltIn for RegExp { .name("get source") .constructor(false) .build(); - let regexp_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().regexp_object().clone(), + context + .intrinsics() + .standard_constructors() + .regexp() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -148,11 +149,10 @@ impl BuiltIn for RegExp { .accessor("sticky", Some(get_sticky), None, flag_attributes) .accessor("flags", Some(get_flags), None, flag_attributes) .accessor("source", Some(get_source), None, flag_attributes) - .build(); - // TODO: add them RegExp accessor properties - - regexp_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -232,11 +232,11 @@ impl RegExp { /// `22.2.3.2.1 RegExpAlloc ( newTarget )` /// /// More information: - /// - [ECMAScript reference][spec] + /// - [ECMAScript reference][spec]regexp /// /// [spec]: https://tc39.es/ecma262/#sec-regexpalloc fn alloc(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { - let proto = get_prototype_from_constructor(this, StandardObjects::regexp_object, context)?; + let proto = get_prototype_from_constructor(this, StandardConstructors::regexp, context)?; Ok(JsObject::from_proto_and_data(proto, ObjectData::ordinary()).into()) } @@ -349,7 +349,11 @@ impl RegExp { if JsObject::equals( object, - &context.standard_objects().regexp_object().prototype, + &context + .intrinsics() + .standard_constructors() + .regexp() + .prototype, ) { return Ok(JsValue::undefined()); } @@ -570,7 +574,13 @@ impl RegExp { // b. Otherwise, throw a TypeError exception. if JsValue::same_value( this, - &JsValue::new(context.standard_objects().regexp_object().prototype()), + &JsValue::new( + context + .intrinsics() + .standard_constructors() + .regexp() + .prototype(), + ), ) { Ok(JsValue::new("(?:)")) } else { @@ -1128,7 +1138,7 @@ impl RegExp { let arg_str = args.get_or_undefined(0).to_string(context)?; // 4. Let C be ? SpeciesConstructor(R, %RegExp%). - let c = regexp.species_constructor(StandardObjects::regexp_object, context)?; + let c = regexp.species_constructor(StandardConstructors::regexp, context)?; // 5. Let flags be ? ToString(? Get(R, "flags")). let flags = regexp.get("flags", context)?.to_string(context)?; @@ -1507,7 +1517,7 @@ impl RegExp { .to_string(context)?; // 4. Let C be ? SpeciesConstructor(rx, %RegExp%). - let constructor = rx.species_constructor(StandardObjects::regexp_object, context)?; + let constructor = rx.species_constructor(StandardConstructors::regexp, context)?; // 5. Let flags be ? ToString(? Get(rx, "flags")). let flags = rx.get("flags", context)?.to_string(context)?; diff --git a/boa_engine/src/builtins/regexp/regexp_string_iterator.rs b/boa_engine/src/builtins/regexp/regexp_string_iterator.rs index 993d685d5af..620d26640b8 100644 --- a/boa_engine/src/builtins/regexp/regexp_string_iterator.rs +++ b/boa_engine/src/builtins/regexp/regexp_string_iterator.rs @@ -69,7 +69,11 @@ impl RegExpStringIterator { // 5. Return ! CreateIteratorFromClosure(closure, "%RegExpStringIteratorPrototype%", %RegExpStringIteratorPrototype%). let regexp_string_iterator = JsObject::from_proto_and_data( - context.iterator_prototypes().regexp_string_iterator(), + context + .intrinsics() + .objects() + .iterator_prototypes() + .regexp_string_iterator(), ObjectData::reg_exp_string_iterator(Self::new(matcher, string, global, unicode)), ); diff --git a/boa_engine/src/builtins/set/mod.rs b/boa_engine/src/builtins/set/mod.rs index fff3de1f9d7..85a69180811 100644 --- a/boa_engine/src/builtins/set/mod.rs +++ b/boa_engine/src/builtins/set/mod.rs @@ -14,7 +14,7 @@ use self::{ordered_set::OrderedSet, set_iterator::SetIterator}; use super::JsArgs; use crate::{ builtins::BuiltIn, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, FunctionBuilder, JsObject, ObjectData, @@ -24,6 +24,7 @@ use crate::{ Context, JsResult, JsValue, }; use boa_profiler::Profiler; +use tap::{Conv, Pipe}; pub mod ordered_set; pub mod set_iterator; @@ -36,11 +37,7 @@ pub(crate) struct Set(OrderedSet); impl BuiltIn for Set { const NAME: &'static str = "Set"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let get_species = FunctionBuilder::native(context, Self::get_species) @@ -63,10 +60,10 @@ impl BuiltIn for Set { .constructor(false) .build(); - let set_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().set_object().clone(), + context.intrinsics().standard_constructors().set().clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -103,9 +100,9 @@ impl BuiltIn for Set { Self::NAME, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .build(); - - set_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -127,7 +124,7 @@ impl Set { // 2. Let set be ? OrdinaryCreateFromConstructor(NewTarget, "%Set.prototype%", « [[SetData]] »). // 3. Set set.[[SetData]] to a new empty List. let prototype = - get_prototype_from_constructor(new_target, StandardObjects::set_object, context)?; + get_prototype_from_constructor(new_target, StandardConstructors::set, context)?; let set = JsObject::from_proto_and_data(prototype, ObjectData::set(OrderedSet::default())); // 4. If iterable is either undefined or null, return set. diff --git a/boa_engine/src/builtins/set/set_iterator.rs b/boa_engine/src/builtins/set/set_iterator.rs index 2a38e69a253..07b2f5e2c72 100644 --- a/boa_engine/src/builtins/set/set_iterator.rs +++ b/boa_engine/src/builtins/set/set_iterator.rs @@ -47,7 +47,11 @@ impl SetIterator { context: &Context, ) -> JsValue { let set_iterator = JsObject::from_proto_and_data( - context.iterator_prototypes().set_iterator(), + context + .intrinsics() + .objects() + .iterator_prototypes() + .set_iterator(), ObjectData::set_iterator(Self::new(set, kind)), ); set_iterator.into() diff --git a/boa_engine/src/builtins/string/mod.rs b/boa_engine/src/builtins/string/mod.rs index a62a6c5ff2f..6e57c052800 100644 --- a/boa_engine/src/builtins/string/mod.rs +++ b/boa_engine/src/builtins/string/mod.rs @@ -16,7 +16,7 @@ mod tests; use super::JsArgs; use crate::{ builtins::{string::string_iterator::StringIterator, Array, BuiltIn, Number, RegExp}, - context::StandardObjects, + context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData, }, @@ -31,6 +31,7 @@ use std::{ cmp::{max, min}, string::String as StdString, }; +use tap::{Conv, Pipe}; use unicode_normalization::UnicodeNormalization; #[derive(Clone, Copy, Eq, PartialEq)] @@ -100,20 +101,20 @@ pub(crate) struct String; impl BuiltIn for String { const NAME: &'static str = "String"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let symbol_iterator = WellKnownSymbols::iterator(); let attribute = Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT; - let string_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().string_object().clone(), + context + .intrinsics() + .standard_constructors() + .string() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -152,9 +153,9 @@ impl BuiltIn for String { .method(Self::iterator, (symbol_iterator, "[Symbol.iterator]"), 0) .method(Self::search, "search", 1) .method(Self::at, "at", 1) - .build(); - - string_object.into() + .build() + .conv::() + .pipe(Some) } } @@ -197,9 +198,7 @@ impl String { } let prototype = - get_prototype_from_constructor(new_target, StandardObjects::string_object, context)?; - - // 4. Return ! StringCreate(s, ? GetPrototypeFromConstructor(NewTarget, "%String.prototype%")). + get_prototype_from_constructor(new_target, StandardConstructors::string, context)?; Ok(Self::string_create(string, prototype, context).into()) } diff --git a/boa_engine/src/builtins/string/string_iterator.rs b/boa_engine/src/builtins/string/string_iterator.rs index e798a00ba0f..31fd9c00f99 100644 --- a/boa_engine/src/builtins/string/string_iterator.rs +++ b/boa_engine/src/builtins/string/string_iterator.rs @@ -26,7 +26,11 @@ impl StringIterator { pub fn create_string_iterator(string: JsValue, context: &mut Context) -> JsResult { let string_iterator = JsObject::from_proto_and_data( - context.iterator_prototypes().string_iterator(), + context + .intrinsics() + .objects() + .iterator_prototypes() + .string_iterator(), ObjectData::string_iterator(Self::new(string)), ); Ok(string_iterator.into()) diff --git a/boa_engine/src/builtins/symbol/mod.rs b/boa_engine/src/builtins/symbol/mod.rs index 4df82b7a6e5..5466bbc574b 100644 --- a/boa_engine/src/builtins/symbol/mod.rs +++ b/boa_engine/src/builtins/symbol/mod.rs @@ -30,6 +30,7 @@ use crate::{ use boa_profiler::Profiler; use rustc_hash::FxHashMap; use std::cell::RefCell; +use tap::{Conv, Pipe}; thread_local! { static GLOBAL_SYMBOL_REGISTRY: RefCell = RefCell::new(GlobalSymbolRegistry::new()); @@ -74,11 +75,7 @@ pub struct Symbol; impl BuiltIn for Symbol { const NAME: &'static str = "Symbol"; - const ATTRIBUTE: Attribute = Attribute::WRITABLE - .union(Attribute::NON_ENUMERABLE) - .union(Attribute::CONFIGURABLE); - - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); let symbol_async_iterator = WellKnownSymbols::async_iterator(); @@ -108,10 +105,14 @@ impl BuiltIn for Symbol { .constructor(false) .build(); - let symbol_object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().symbol_object().clone(), + context + .intrinsics() + .standard_constructors() + .symbol() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -150,9 +151,9 @@ impl BuiltIn for Symbol { to_primitive, Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) - .build(); - - symbol_object.into() + .build() + .conv::() + .pipe(Some) } } diff --git a/boa_engine/src/builtins/typed_array/mod.rs b/boa_engine/src/builtins/typed_array/mod.rs index e6d783f9d05..77925272618 100644 --- a/boa_engine/src/builtins/typed_array/mod.rs +++ b/boa_engine/src/builtins/typed_array/mod.rs @@ -19,7 +19,7 @@ use crate::{ typed_array::integer_indexed_object::{ContentType, IntegerIndexed}, Array, ArrayIterator, BuiltIn, JsArgs, }, - context::{StandardConstructor, StandardObjects}, + context::intrinsics::{StandardConstructor, StandardConstructors}, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, FunctionBuilder, JsObject, ObjectData, @@ -34,6 +34,8 @@ use boa_profiler::Profiler; use num_traits::{Signed, Zero}; use std::cmp::Ordering; +use tap::{Conv, Pipe}; + pub mod integer_indexed_object; macro_rules! typed_array { @@ -49,21 +51,33 @@ macro_rules! typed_array { .union(Attribute::NON_ENUMERABLE) .union(Attribute::CONFIGURABLE); - fn init(context: &mut Context) -> JsValue { + fn init(context: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); - let typed_array_constructor = context.typed_array_constructor().constructor(); - let typed_array_constructor_proto = context.typed_array_constructor().prototype(); + let typed_array_constructor = context + .intrinsics() + .standard_constructors() + .typed_array() + .constructor(); + let typed_array_constructor_proto = context + .intrinsics() + .standard_constructors() + .typed_array() + .prototype(); let get_species = FunctionBuilder::native(context, TypedArray::get_species) .name("get [Symbol.species]") .constructor(false) .build(); - ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().$global_object_name().clone(), + context + .intrinsics() + .standard_constructors() + .$global_object_name() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -86,7 +100,8 @@ macro_rules! typed_array { .custom_prototype(typed_array_constructor) .inherit(typed_array_constructor_proto) .build() - .into() + .conv::() + .pipe(Some) } } @@ -116,7 +131,7 @@ macro_rules! typed_array { let constructor_name = TypedArrayKind::$variant; // 3. Let proto be "%TypedArray.prototype%". - let proto = StandardObjects::$global_object_name; + let proto = StandardConstructors::$global_object_name; // 4. Let numberOfArgs be the number of elements in args. let number_of_args = args.len(); @@ -229,12 +244,9 @@ macro_rules! typed_array { #[derive(Debug, Clone, Copy)] pub(crate) struct TypedArray; -impl TypedArray { +impl BuiltIn for TypedArray { const NAME: &'static str = "TypedArray"; - - const LENGTH: usize = 0; - - pub(crate) fn init(context: &mut Context) -> JsObject { + fn init(context: &mut Context) -> Option { let get_species = FunctionBuilder::native(context, Self::get_species) .name("get [Symbol.species]") .constructor(false) @@ -271,10 +283,14 @@ impl TypedArray { .constructor(false) .build(); - let object = ConstructorBuilder::with_standard_object( + ConstructorBuilder::with_standard_constructor( context, Self::constructor, - context.standard_objects().typed_array_object().clone(), + context + .intrinsics() + .standard_constructors() + .typed_array() + .clone(), ) .name(Self::NAME) .length(Self::LENGTH) @@ -356,8 +372,11 @@ impl TypedArray { .method(Array::to_string, "toString", 0) .build(); - object + None } +} +impl TypedArray { + const LENGTH: usize = 0; /// `23.2.1.1 %TypedArray% ( )` /// @@ -2011,8 +2030,9 @@ impl TypedArray { // b. Set srcBuffer to ? CloneArrayBuffer(srcBuffer, srcByteOffset, srcByteLength, %ArrayBuffer%). // c. NOTE: %ArrayBuffer% is used to clone srcBuffer because is it known to not have any observable side-effects. let array_buffer_constructor = context - .standard_objects() - .array_buffer_object() + .intrinsics() + .standard_constructors() + .array_buffer() .constructor() .into(); let s = src_buffer_obj @@ -2815,17 +2835,17 @@ impl TypedArray { ) -> JsResult { // 1. Let defaultConstructor be the intrinsic object listed in column one of Table 73 for exemplar.[[TypedArrayName]]. let default_constructor = match typed_array_name { - TypedArrayKind::Int8 => StandardObjects::typed_int8_array_object, - TypedArrayKind::Uint8 => StandardObjects::typed_uint8_array_object, - TypedArrayKind::Uint8Clamped => StandardObjects::typed_uint8clamped_array_object, - TypedArrayKind::Int16 => StandardObjects::typed_int16_array_object, - TypedArrayKind::Uint16 => StandardObjects::typed_uint16_array_object, - TypedArrayKind::Int32 => StandardObjects::typed_int32_array_object, - TypedArrayKind::Uint32 => StandardObjects::typed_uint32_array_object, - TypedArrayKind::BigInt64 => StandardObjects::typed_bigint64_array_object, - TypedArrayKind::BigUint64 => StandardObjects::typed_biguint64_array_object, - TypedArrayKind::Float32 => StandardObjects::typed_float32_array_object, - TypedArrayKind::Float64 => StandardObjects::typed_float64_array_object, + TypedArrayKind::Int8 => StandardConstructors::typed_int8_array, + TypedArrayKind::Uint8 => StandardConstructors::typed_uint8_array, + TypedArrayKind::Uint8Clamped => StandardConstructors::typed_uint8clamped_array, + TypedArrayKind::Int16 => StandardConstructors::typed_int16_array, + TypedArrayKind::Uint16 => StandardConstructors::typed_uint16_array, + TypedArrayKind::Int32 => StandardConstructors::typed_int32_array, + TypedArrayKind::Uint32 => StandardConstructors::typed_uint32_array, + TypedArrayKind::BigInt64 => StandardConstructors::typed_bigint64_array, + TypedArrayKind::BigUint64 => StandardConstructors::typed_biguint64_array, + TypedArrayKind::Float32 => StandardConstructors::typed_float32_array, + TypedArrayKind::Float64 => StandardConstructors::typed_float64_array, }; // 2. Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor). @@ -2912,8 +2932,9 @@ impl TypedArray { // 5. Let data be ? AllocateArrayBuffer(%ArrayBuffer%, byteLength). let data = ArrayBuffer::allocate( &context - .standard_objects() - .array_buffer_object() + .intrinsics() + .standard_constructors() + .array_buffer() .constructor() .into(), byte_length, @@ -2982,7 +3003,7 @@ impl TypedArray { context: &mut Context, ) -> JsResult where - P: FnOnce(&StandardObjects) -> &StandardConstructor, + P: FnOnce(&StandardConstructors) -> &StandardConstructor, { // 1. Let proto be ? GetPrototypeFromConstructor(newTarget, defaultProto). let proto = get_prototype_from_constructor(new_target, default_proto, context)?; @@ -3062,7 +3083,7 @@ impl TypedArray { // 13. Else, // a. Let bufferConstructor be %ArrayBuffer%. let buffer_constructor = - src_data_obj.species_constructor(StandardObjects::array_buffer_object, context)?; + src_data_obj.species_constructor(StandardConstructors::array_buffer, context)?; let src_data_obj_b = src_data_obj.borrow(); let src_data = src_data_obj_b @@ -3352,49 +3373,29 @@ impl TypedArrayKind { } } -typed_array!(Int8Array, Int8, "Int8Array", typed_int8_array_object); -typed_array!(Uint8Array, Uint8, "Uint8Array", typed_uint8_array_object); +typed_array!(Int8Array, Int8, "Int8Array", typed_int8_array); +typed_array!(Uint8Array, Uint8, "Uint8Array", typed_uint8_array); typed_array!( Uint8ClampedArray, Uint8Clamped, "Uint8ClampedArray", - typed_uint8clamped_array_object -); -typed_array!(Int16Array, Int16, "Int16Array", typed_int16_array_object); -typed_array!( - Uint16Array, - Uint16, - "Uint16Array", - typed_uint16_array_object -); -typed_array!(Int32Array, Int32, "Int32Array", typed_int32_array_object); -typed_array!( - Uint32Array, - Uint32, - "Uint32Array", - typed_uint32_array_object + typed_uint8clamped_array ); +typed_array!(Int16Array, Int16, "Int16Array", typed_int16_array); +typed_array!(Uint16Array, Uint16, "Uint16Array", typed_uint16_array); +typed_array!(Int32Array, Int32, "Int32Array", typed_int32_array); +typed_array!(Uint32Array, Uint32, "Uint32Array", typed_uint32_array); typed_array!( BigInt64Array, BigInt64, "BigInt64Array", - typed_bigint64_array_object + typed_bigint64_array ); typed_array!( BigUint64Array, BigUint64, "BigUint64Array", - typed_biguint64_array_object -); -typed_array!( - Float32Array, - Float32, - "Float32Array", - typed_float32_array_object -); -typed_array!( - Float64Array, - Float64, - "Float64Array", - typed_float64_array_object + typed_biguint64_array ); +typed_array!(Float32Array, Float32, "Float32Array", typed_float32_array); +typed_array!(Float64Array, Float64, "Float64Array", typed_float64_array); diff --git a/boa_engine/src/builtins/undefined/mod.rs b/boa_engine/src/builtins/undefined/mod.rs index 0f9affc6a4d..9b3e329765e 100644 --- a/boa_engine/src/builtins/undefined/mod.rs +++ b/boa_engine/src/builtins/undefined/mod.rs @@ -26,9 +26,9 @@ impl BuiltIn for Undefined { .union(Attribute::NON_ENUMERABLE) .union(Attribute::PERMANENT); - fn init(_: &mut Context) -> JsValue { + fn init(_: &mut Context) -> Option { let _timer = Profiler::global().start_event(Self::NAME, "init"); - JsValue::undefined() + Some(JsValue::undefined()) } } diff --git a/boa_engine/src/context/intrinsics.rs b/boa_engine/src/context/intrinsics.rs new file mode 100644 index 00000000000..129b16f60ab --- /dev/null +++ b/boa_engine/src/context/intrinsics.rs @@ -0,0 +1,368 @@ +use crate::{ + builtins::{error::r#type::create_throw_type_error, iterable::IteratorPrototypes}, + object::{JsObject, ObjectData}, + Context, +}; + +#[derive(Debug, Default)] +pub struct Intrinsics { + /// Cached standard constructors + pub(super) standard_constructors: StandardConstructors, + /// Cached intrinsic objects + pub(super) objects: IntrinsicObjects, +} + +impl Intrinsics { + /// Return the cached intrinsic objects. + #[inline] + pub fn objects(&self) -> &IntrinsicObjects { + &self.objects + } + + /// Return the core standard objects. + #[inline] + pub fn standard_constructors(&self) -> &StandardConstructors { + &self.standard_constructors + } +} + +/// Store a builtin constructor (such as `Object`) and its corresponding prototype. +#[derive(Debug, Clone)] +pub struct StandardConstructor { + pub(crate) constructor: JsObject, + pub(crate) prototype: JsObject, +} + +impl Default for StandardConstructor { + fn default() -> Self { + Self { + constructor: JsObject::empty(), + prototype: JsObject::empty(), + } + } +} + +impl StandardConstructor { + /// Build a constructor with a defined prototype. + fn with_prototype(prototype: JsObject) -> Self { + Self { + constructor: JsObject::empty(), + prototype, + } + } + + /// Return the constructor object. + /// + /// This is the same as `Object`, `Array`, etc. + #[inline] + pub fn constructor(&self) -> JsObject { + self.constructor.clone() + } + + /// Return the prototype of the constructor object. + /// + /// This is the same as `Object.prototype`, `Array.prototype`, etc + #[inline] + pub fn prototype(&self) -> JsObject { + self.prototype.clone() + } +} + +/// Cached core standard constructors. +#[derive(Debug, Clone)] +pub struct StandardConstructors { + object: StandardConstructor, + proxy: StandardConstructor, + function: StandardConstructor, + generator: StandardConstructor, + generator_function: StandardConstructor, + array: StandardConstructor, + bigint: StandardConstructor, + number: StandardConstructor, + boolean: StandardConstructor, + string: StandardConstructor, + regexp: StandardConstructor, + symbol: StandardConstructor, + error: StandardConstructor, + type_error: StandardConstructor, + reference_error: StandardConstructor, + range_error: StandardConstructor, + syntax_error: StandardConstructor, + eval_error: StandardConstructor, + uri_error: StandardConstructor, + map: StandardConstructor, + set: StandardConstructor, + typed_array: StandardConstructor, + typed_int8_array: StandardConstructor, + typed_uint8_array: StandardConstructor, + typed_uint8clamped_array: StandardConstructor, + typed_int16_array: StandardConstructor, + typed_uint16_array: StandardConstructor, + typed_int32_array: StandardConstructor, + typed_uint32_array: StandardConstructor, + typed_bigint64_array: StandardConstructor, + typed_biguint64_array: StandardConstructor, + typed_float32_array: StandardConstructor, + typed_float64_array: StandardConstructor, + array_buffer: StandardConstructor, + data_view: StandardConstructor, +} + +impl Default for StandardConstructors { + fn default() -> Self { + Self { + object: StandardConstructor::default(), + proxy: StandardConstructor::default(), + function: StandardConstructor::default(), + generator: StandardConstructor::default(), + generator_function: StandardConstructor::default(), + array: StandardConstructor::default(), + bigint: StandardConstructor::default(), + number: StandardConstructor::with_prototype(JsObject::from_proto_and_data( + None, + ObjectData::number(0.0), + )), + boolean: StandardConstructor::with_prototype(JsObject::from_proto_and_data( + None, + ObjectData::boolean(false), + )), + string: StandardConstructor::with_prototype(JsObject::from_proto_and_data( + None, + ObjectData::string("".into()), + )), + regexp: StandardConstructor::default(), + symbol: StandardConstructor::default(), + error: StandardConstructor::default(), + type_error: StandardConstructor::default(), + reference_error: StandardConstructor::default(), + range_error: StandardConstructor::default(), + syntax_error: StandardConstructor::default(), + eval_error: StandardConstructor::default(), + uri_error: StandardConstructor::default(), + map: StandardConstructor::default(), + set: StandardConstructor::default(), + typed_array: StandardConstructor::default(), + typed_int8_array: StandardConstructor::default(), + typed_uint8_array: StandardConstructor::default(), + typed_uint8clamped_array: StandardConstructor::default(), + typed_int16_array: StandardConstructor::default(), + typed_uint16_array: StandardConstructor::default(), + typed_int32_array: StandardConstructor::default(), + typed_uint32_array: StandardConstructor::default(), + typed_bigint64_array: StandardConstructor::default(), + typed_biguint64_array: StandardConstructor::default(), + typed_float32_array: StandardConstructor::default(), + typed_float64_array: StandardConstructor::default(), + array_buffer: StandardConstructor::default(), + data_view: StandardConstructor::default(), + } + } +} + +impl StandardConstructors { + #[inline] + pub fn object(&self) -> &StandardConstructor { + &self.object + } + + #[inline] + pub fn proxy(&self) -> &StandardConstructor { + &self.proxy + } + + #[inline] + pub fn function(&self) -> &StandardConstructor { + &self.function + } + + #[inline] + pub fn generator(&self) -> &StandardConstructor { + &self.generator + } + + #[inline] + pub fn generator_function(&self) -> &StandardConstructor { + &self.generator_function + } + + #[inline] + pub fn array(&self) -> &StandardConstructor { + &self.array + } + + #[inline] + pub fn bigint_object(&self) -> &StandardConstructor { + &self.bigint + } + + #[inline] + pub fn number(&self) -> &StandardConstructor { + &self.number + } + + #[inline] + pub fn boolean(&self) -> &StandardConstructor { + &self.boolean + } + + #[inline] + pub fn string(&self) -> &StandardConstructor { + &self.string + } + + #[inline] + pub fn regexp(&self) -> &StandardConstructor { + &self.regexp + } + + #[inline] + pub fn symbol(&self) -> &StandardConstructor { + &self.symbol + } + + #[inline] + pub fn error(&self) -> &StandardConstructor { + &self.error + } + + #[inline] + pub fn reference_error(&self) -> &StandardConstructor { + &self.reference_error + } + + #[inline] + pub fn type_error(&self) -> &StandardConstructor { + &self.type_error + } + + #[inline] + pub fn range_error(&self) -> &StandardConstructor { + &self.range_error + } + + #[inline] + pub fn syntax_error(&self) -> &StandardConstructor { + &self.syntax_error + } + + #[inline] + pub fn eval_error(&self) -> &StandardConstructor { + &self.eval_error + } + + #[inline] + pub fn uri_error(&self) -> &StandardConstructor { + &self.uri_error + } + + #[inline] + pub fn map(&self) -> &StandardConstructor { + &self.map + } + + #[inline] + pub fn set(&self) -> &StandardConstructor { + &self.set + } + + #[inline] + pub fn typed_array(&self) -> &StandardConstructor { + &self.typed_array + } + + #[inline] + pub fn typed_int8_array(&self) -> &StandardConstructor { + &self.typed_int8_array + } + + #[inline] + pub fn typed_uint8_array(&self) -> &StandardConstructor { + &self.typed_uint8_array + } + + #[inline] + pub fn typed_uint8clamped_array(&self) -> &StandardConstructor { + &self.typed_uint8clamped_array + } + + #[inline] + pub fn typed_int16_array(&self) -> &StandardConstructor { + &self.typed_int16_array + } + + #[inline] + pub fn typed_uint16_array(&self) -> &StandardConstructor { + &self.typed_uint16_array + } + + #[inline] + pub fn typed_uint32_array(&self) -> &StandardConstructor { + &self.typed_uint32_array + } + + #[inline] + pub fn typed_int32_array(&self) -> &StandardConstructor { + &self.typed_int32_array + } + + #[inline] + pub fn typed_bigint64_array(&self) -> &StandardConstructor { + &self.typed_bigint64_array + } + + #[inline] + pub fn typed_biguint64_array(&self) -> &StandardConstructor { + &self.typed_biguint64_array + } + + #[inline] + pub fn typed_float32_array(&self) -> &StandardConstructor { + &self.typed_float32_array + } + + #[inline] + pub fn typed_float64_array(&self) -> &StandardConstructor { + &self.typed_float64_array + } + + #[inline] + pub fn array_buffer(&self) -> &StandardConstructor { + &self.array_buffer + } + + #[inline] + pub fn data_view(&self) -> &StandardConstructor { + &self.data_view + } +} + +/// Cached intrinsic objects +#[derive(Debug, Default)] +pub struct IntrinsicObjects { + /// %ThrowTypeError% intrinsic object + throw_type_error: JsObject, + /// Cached iterator prototypes. + iterator_prototypes: IteratorPrototypes, +} + +impl IntrinsicObjects { + /// Initialize the intrinsic objects + pub fn init(context: &mut Context) -> Self { + Self { + throw_type_error: create_throw_type_error(context), + iterator_prototypes: IteratorPrototypes::init(context), + } + } + + /// Get the `%ThrowTypeError%` intrinsic object + #[inline] + pub fn throw_type_error(&self) -> JsObject { + self.throw_type_error.clone() + } + + /// Get the cached iterator prototypes. + #[inline] + pub fn iterator_prototypes(&self) -> &IteratorPrototypes { + &self.iterator_prototypes + } +} diff --git a/boa_engine/src/context.rs b/boa_engine/src/context/mod.rs similarity index 64% rename from boa_engine/src/context.rs rename to boa_engine/src/context/mod.rs index 042a11972c4..58a3fb859bc 100644 --- a/boa_engine/src/context.rs +++ b/boa_engine/src/context/mod.rs @@ -1,10 +1,11 @@ //! Javascript context. +pub mod intrinsics; + +use intrinsics::{IntrinsicObjects, Intrinsics}; + use crate::{ - builtins::{ - self, function::NativeFunctionSignature, intrinsics::IntrinsicObjects, - iterable::IteratorPrototypes, typed_array::TypedArray, - }, + builtins::{self, function::NativeFunctionSignature}, bytecompiler::ByteCompiler, class::{Class, ClassBuilder}, object::{FunctionBuilder, GlobalPropertyMap, JsObject, ObjectData}, @@ -21,316 +22,6 @@ use boa_profiler::Profiler; #[cfg(feature = "console")] use crate::builtins::console::Console; -/// Store a builtin constructor (such as `Object`) and its corresponding prototype. -#[derive(Debug, Clone)] -pub struct StandardConstructor { - pub(crate) constructor: JsObject, - pub(crate) prototype: JsObject, -} - -impl Default for StandardConstructor { - fn default() -> Self { - Self { - constructor: JsObject::empty(), - prototype: JsObject::empty(), - } - } -} - -impl StandardConstructor { - /// Build a constructor with a defined prototype. - fn with_prototype(prototype: JsObject) -> Self { - Self { - constructor: JsObject::empty(), - prototype, - } - } - - /// Return the constructor object. - /// - /// This is the same as `Object`, `Array`, etc. - #[inline] - pub fn constructor(&self) -> JsObject { - self.constructor.clone() - } - - /// Return the prototype of the constructor object. - /// - /// This is the same as `Object.prototype`, `Array.prototype`, etc - #[inline] - pub fn prototype(&self) -> JsObject { - self.prototype.clone() - } -} - -/// Cached core standard objects. -#[derive(Debug, Clone)] -pub struct StandardObjects { - object: StandardConstructor, - proxy: StandardConstructor, - function: StandardConstructor, - generator: StandardConstructor, - generator_function: StandardConstructor, - array: StandardConstructor, - bigint: StandardConstructor, - number: StandardConstructor, - boolean: StandardConstructor, - string: StandardConstructor, - regexp: StandardConstructor, - symbol: StandardConstructor, - error: StandardConstructor, - type_error: StandardConstructor, - reference_error: StandardConstructor, - range_error: StandardConstructor, - syntax_error: StandardConstructor, - eval_error: StandardConstructor, - uri_error: StandardConstructor, - map: StandardConstructor, - set: StandardConstructor, - typed_array: StandardConstructor, - typed_int8_array: StandardConstructor, - typed_uint8_array: StandardConstructor, - typed_uint8clamped_array: StandardConstructor, - typed_int16_array: StandardConstructor, - typed_uint16_array: StandardConstructor, - typed_int32_array: StandardConstructor, - typed_uint32_array: StandardConstructor, - typed_bigint64_array: StandardConstructor, - typed_biguint64_array: StandardConstructor, - typed_float32_array: StandardConstructor, - typed_float64_array: StandardConstructor, - array_buffer: StandardConstructor, - data_view: StandardConstructor, -} - -impl Default for StandardObjects { - fn default() -> Self { - Self { - object: StandardConstructor::default(), - proxy: StandardConstructor::default(), - function: StandardConstructor::default(), - generator: StandardConstructor::default(), - generator_function: StandardConstructor::default(), - array: StandardConstructor::default(), - bigint: StandardConstructor::default(), - number: StandardConstructor::with_prototype(JsObject::from_proto_and_data( - None, - ObjectData::number(0.0), - )), - boolean: StandardConstructor::with_prototype(JsObject::from_proto_and_data( - None, - ObjectData::boolean(false), - )), - string: StandardConstructor::with_prototype(JsObject::from_proto_and_data( - None, - ObjectData::string("".into()), - )), - regexp: StandardConstructor::default(), - symbol: StandardConstructor::default(), - error: StandardConstructor::default(), - type_error: StandardConstructor::default(), - reference_error: StandardConstructor::default(), - range_error: StandardConstructor::default(), - syntax_error: StandardConstructor::default(), - eval_error: StandardConstructor::default(), - uri_error: StandardConstructor::default(), - map: StandardConstructor::default(), - set: StandardConstructor::default(), - typed_array: StandardConstructor::default(), - typed_int8_array: StandardConstructor::default(), - typed_uint8_array: StandardConstructor::default(), - typed_uint8clamped_array: StandardConstructor::default(), - typed_int16_array: StandardConstructor::default(), - typed_uint16_array: StandardConstructor::default(), - typed_int32_array: StandardConstructor::default(), - typed_uint32_array: StandardConstructor::default(), - typed_bigint64_array: StandardConstructor::default(), - typed_biguint64_array: StandardConstructor::default(), - typed_float32_array: StandardConstructor::default(), - typed_float64_array: StandardConstructor::default(), - array_buffer: StandardConstructor::default(), - data_view: StandardConstructor::default(), - } - } -} - -impl StandardObjects { - #[inline] - pub fn object_object(&self) -> &StandardConstructor { - &self.object - } - - #[inline] - pub fn proxy_object(&self) -> &StandardConstructor { - &self.proxy - } - - #[inline] - pub fn function_object(&self) -> &StandardConstructor { - &self.function - } - - #[inline] - pub fn generator_object(&self) -> &StandardConstructor { - &self.generator - } - - #[inline] - pub fn generator_function_object(&self) -> &StandardConstructor { - &self.generator_function - } - - #[inline] - pub fn array_object(&self) -> &StandardConstructor { - &self.array - } - - #[inline] - pub fn bigint_object(&self) -> &StandardConstructor { - &self.bigint - } - - #[inline] - pub fn number_object(&self) -> &StandardConstructor { - &self.number - } - - #[inline] - pub fn boolean_object(&self) -> &StandardConstructor { - &self.boolean - } - - #[inline] - pub fn string_object(&self) -> &StandardConstructor { - &self.string - } - - #[inline] - pub fn regexp_object(&self) -> &StandardConstructor { - &self.regexp - } - - #[inline] - pub fn symbol_object(&self) -> &StandardConstructor { - &self.symbol - } - - #[inline] - pub fn error_object(&self) -> &StandardConstructor { - &self.error - } - - #[inline] - pub fn reference_error_object(&self) -> &StandardConstructor { - &self.reference_error - } - - #[inline] - pub fn type_error_object(&self) -> &StandardConstructor { - &self.type_error - } - - #[inline] - pub fn range_error_object(&self) -> &StandardConstructor { - &self.range_error - } - - #[inline] - pub fn syntax_error_object(&self) -> &StandardConstructor { - &self.syntax_error - } - - #[inline] - pub fn eval_error_object(&self) -> &StandardConstructor { - &self.eval_error - } - - #[inline] - pub fn uri_error_object(&self) -> &StandardConstructor { - &self.uri_error - } - - #[inline] - pub fn map_object(&self) -> &StandardConstructor { - &self.map - } - - #[inline] - pub fn set_object(&self) -> &StandardConstructor { - &self.set - } - - #[inline] - pub fn typed_array_object(&self) -> &StandardConstructor { - &self.typed_array - } - - #[inline] - pub fn typed_int8_array_object(&self) -> &StandardConstructor { - &self.typed_int8_array - } - - #[inline] - pub fn typed_uint8_array_object(&self) -> &StandardConstructor { - &self.typed_uint8_array - } - - #[inline] - pub fn typed_uint8clamped_array_object(&self) -> &StandardConstructor { - &self.typed_uint8clamped_array - } - - #[inline] - pub fn typed_int16_array_object(&self) -> &StandardConstructor { - &self.typed_int16_array - } - - #[inline] - pub fn typed_uint16_array_object(&self) -> &StandardConstructor { - &self.typed_uint16_array - } - - #[inline] - pub fn typed_uint32_array_object(&self) -> &StandardConstructor { - &self.typed_uint32_array - } - - #[inline] - pub fn typed_int32_array_object(&self) -> &StandardConstructor { - &self.typed_int32_array - } - - #[inline] - pub fn typed_bigint64_array_object(&self) -> &StandardConstructor { - &self.typed_bigint64_array - } - - #[inline] - pub fn typed_biguint64_array_object(&self) -> &StandardConstructor { - &self.typed_biguint64_array - } - - #[inline] - pub fn typed_float32_array_object(&self) -> &StandardConstructor { - &self.typed_float32_array - } - - #[inline] - pub fn typed_float64_array_object(&self) -> &StandardConstructor { - &self.typed_float64_array - } - - #[inline] - pub fn array_buffer_object(&self) -> &StandardConstructor { - &self.array_buffer - } - - #[inline] - pub fn data_view_object(&self) -> &StandardConstructor { - &self.data_view - } -} - /// Javascript context. It is the primary way to interact with the runtime. /// /// `Context`s constructed in a thread share the same runtime, therefore it @@ -388,17 +79,8 @@ pub struct Context { #[cfg(feature = "console")] console: Console, - /// Cached iterator prototypes. - iterator_prototypes: IteratorPrototypes, - - /// Cached TypedArray constructor. - typed_array_constructor: StandardConstructor, - - /// Cached standard objects and their prototypes. - standard_objects: StandardObjects, - - /// Cached intrinsic objects - intrinsic_objects: IntrinsicObjects, + /// Intrinsic objects + intrinsics: Intrinsics, /// Whether or not global strict mode is active. strict: bool, @@ -413,10 +95,7 @@ impl Default for Context { interner: Interner::default(), #[cfg(feature = "console")] console: Console::default(), - iterator_prototypes: IteratorPrototypes::default(), - typed_array_constructor: StandardConstructor::default(), - standard_objects: StandardObjects::default(), - intrinsic_objects: IntrinsicObjects::default(), + intrinsics: Intrinsics::default(), strict: false, vm: Vm { frame: None, @@ -429,18 +108,8 @@ impl Default for Context { // Add new builtIns to Context Realm // At a later date this can be removed from here and called explicitly, // but for now we almost always want these default builtins - let typed_array_constructor_constructor = TypedArray::init(&mut context); - let typed_array_constructor_prototype = typed_array_constructor_constructor - .get("prototype", &mut context) - .expect("prototype must exist") - .as_object() - .expect("prototype must be object") - .clone(); - context.typed_array_constructor.constructor = typed_array_constructor_constructor; - context.typed_array_constructor.prototype = typed_array_constructor_prototype; - context.iterator_prototypes = IteratorPrototypes::init(&mut context); context.create_intrinsics(); - context.intrinsic_objects = IntrinsicObjects::init(&mut context); + context.intrinsics.objects = IntrinsicObjects::init(&mut context); context } } @@ -504,7 +173,10 @@ impl Context { #[inline] pub fn construct_object(&self) -> JsObject { JsObject::from_proto_and_data( - self.standard_objects().object_object().prototype(), + self.intrinsics() + .standard_constructors() + .object() + .prototype(), ObjectData::ordinary(), ) } @@ -554,7 +226,12 @@ impl Context { M: Into>, { crate::builtins::error::Error::constructor( - &self.standard_objects().error_object().constructor().into(), + &self + .intrinsics() + .standard_constructors() + .error() + .constructor() + .into(), &[message.into().into()], self, ) @@ -578,8 +255,9 @@ impl Context { { crate::builtins::error::RangeError::constructor( &self - .standard_objects() - .range_error_object() + .intrinsics() + .standard_constructors() + .range_error() .constructor() .into(), &[message.into().into()], @@ -605,8 +283,9 @@ impl Context { { crate::builtins::error::TypeError::constructor( &self - .standard_objects() - .type_error_object() + .intrinsics() + .standard_constructors() + .type_error() .constructor() .into(), &[message.into().into()], @@ -632,8 +311,9 @@ impl Context { { crate::builtins::error::ReferenceError::constructor( &self - .standard_objects() - .reference_error_object() + .intrinsics() + .standard_constructors() + .reference_error() .constructor() .into(), &[message.into().into()], @@ -659,8 +339,9 @@ impl Context { { crate::builtins::error::SyntaxError::constructor( &self - .standard_objects() - .syntax_error_object() + .intrinsics() + .standard_constructors() + .syntax_error() .constructor() .into(), &[message.into().into()], @@ -685,8 +366,9 @@ impl Context { { crate::builtins::error::EvalError::constructor( &self - .standard_objects() - .eval_error_object() + .intrinsics() + .standard_constructors() + .eval_error() .constructor() .into(), &[message.into().into()], @@ -702,8 +384,9 @@ impl Context { { crate::builtins::error::UriError::constructor( &self - .standard_objects() - .uri_error_object() + .intrinsics() + .standard_constructors() + .uri_error() .constructor() .into(), &[message.into().into()], @@ -1035,28 +718,10 @@ impl Context { Ok(result) } - /// Return the cached iterator prototypes. - #[inline] - pub fn iterator_prototypes(&self) -> &IteratorPrototypes { - &self.iterator_prototypes - } - - /// Return the cached `TypedArray` constructor. - #[inline] - pub(crate) fn typed_array_constructor(&self) -> &StandardConstructor { - &self.typed_array_constructor - } - - /// Return the core standard objects. - #[inline] - pub fn standard_objects(&self) -> &StandardObjects { - &self.standard_objects - } - - /// Return the intrinsic objects. + /// Return the intrinsic constructors and objects. #[inline] - pub fn intrinsics(&self) -> &IntrinsicObjects { - &self.intrinsic_objects + pub fn intrinsics(&self) -> &Intrinsics { + &self.intrinsics } /// Set the value of trace on the context diff --git a/boa_engine/src/object/internal_methods/mod.rs b/boa_engine/src/object/internal_methods/mod.rs index ead2912ad2d..c0b33c745d0 100644 --- a/boa_engine/src/object/internal_methods/mod.rs +++ b/boa_engine/src/object/internal_methods/mod.rs @@ -7,7 +7,7 @@ use super::{JsPrototype, PROTOTYPE}; use crate::{ - context::{StandardConstructor, StandardObjects}, + context::intrinsics::{StandardConstructor, StandardConstructors}, object::JsObject, property::{DescriptorKind, PropertyDescriptor, PropertyKey}, value::JsValue, @@ -951,7 +951,7 @@ pub(crate) fn get_prototype_from_constructor( context: &mut Context, ) -> JsResult where - F: FnOnce(&StandardObjects) -> &StandardConstructor, + F: FnOnce(&StandardConstructors) -> &StandardConstructor, { let _timer = Profiler::global().start_event("Object::get_prototype_from_constructor", "object"); // 1. Assert: intrinsicDefaultProto is this specification's name of an intrinsic @@ -968,5 +968,5 @@ where // TODO: handle realms // a. Let realm be ? GetFunctionRealm(constructor). // b. Set proto to realm's intrinsic object named intrinsicDefaultProto. - Ok(default(context.standard_objects()).prototype()) + Ok(default(context.intrinsics().standard_constructors()).prototype()) } diff --git a/boa_engine/src/object/jsarray.rs b/boa_engine/src/object/jsarray.rs index 17ddabf88af..1f69efdc738 100644 --- a/boa_engine/src/object/jsarray.rs +++ b/boa_engine/src/object/jsarray.rs @@ -1,6 +1,7 @@ use crate::{ builtins::Array, object::{JsObject, JsObjectType}, + value::IntoOrUndefined, Context, JsResult, JsString, JsValue, }; use boa_gc::{Finalize, Trace}; @@ -116,7 +117,12 @@ impl JsArray { #[inline] pub fn join(&self, separator: Option, context: &mut Context) -> JsResult { - Array::join(&self.inner.clone().into(), &[separator.into()], context).map(|x| { + Array::join( + &self.inner.clone().into(), + &[separator.into_or_undefined()], + context, + ) + .map(|x| { x.as_string() .cloned() .expect("Array.prototype.join always returns string") @@ -136,7 +142,11 @@ impl JsArray { { Array::fill( &self.inner.clone().into(), - &[value.into(), start.into(), end.into()], + &[ + value.into(), + start.into_or_undefined(), + end.into_or_undefined(), + ], context, )?; Ok(self.clone()) @@ -154,7 +164,7 @@ impl JsArray { { let index = Array::index_of( &self.inner.clone().into(), - &[search_element.into(), from_index.into()], + &[search_element.into(), from_index.into_or_undefined()], context, )? .as_number() @@ -180,7 +190,7 @@ impl JsArray { { let index = Array::last_index_of( &self.inner.clone().into(), - &[search_element.into(), from_index.into()], + &[search_element.into(), from_index.into_or_undefined()], context, )? .as_number() @@ -203,7 +213,7 @@ impl JsArray { ) -> JsResult { Array::find( &self.inner.clone().into(), - &[predicate.into(), this_arg.into()], + &[predicate.into(), this_arg.into_or_undefined()], context, ) } @@ -217,7 +227,7 @@ impl JsArray { ) -> JsResult { let object = Array::filter( &self.inner.clone().into(), - &[callback.into(), this_arg.into()], + &[callback.into(), this_arg.into_or_undefined()], context, )? .as_object() @@ -236,7 +246,7 @@ impl JsArray { ) -> JsResult { let object = Array::map( &self.inner.clone().into(), - &[callback.into(), this_arg.into()], + &[callback.into(), this_arg.into_or_undefined()], context, )? .as_object() @@ -255,7 +265,7 @@ impl JsArray { ) -> JsResult { let result = Array::every( &self.inner.clone().into(), - &[callback.into(), this_arg.into()], + &[callback.into(), this_arg.into_or_undefined()], context, )? .as_boolean() @@ -273,7 +283,7 @@ impl JsArray { ) -> JsResult { let result = Array::some( &self.inner.clone().into(), - &[callback.into(), this_arg.into()], + &[callback.into(), this_arg.into_or_undefined()], context, )? .as_boolean() @@ -284,7 +294,11 @@ impl JsArray { #[inline] pub fn sort(&self, compare_fn: Option, context: &mut Context) -> JsResult { - Array::sort(&self.inner.clone().into(), &[compare_fn.into()], context)?; + Array::sort( + &self.inner.clone().into(), + &[compare_fn.into_or_undefined()], + context, + )?; Ok(self.clone()) } @@ -298,7 +312,7 @@ impl JsArray { ) -> JsResult { let object = Array::slice( &self.inner.clone().into(), - &[start.into(), end.into()], + &[start.into_or_undefined(), end.into_or_undefined()], context, )? .as_object() @@ -317,7 +331,7 @@ impl JsArray { ) -> JsResult { Array::reduce( &self.inner.clone().into(), - &[callback.into(), initial_value.into()], + &[callback.into(), initial_value.into_or_undefined()], context, ) } @@ -331,7 +345,7 @@ impl JsArray { ) -> JsResult { Array::reduce_right( &self.inner.clone().into(), - &[callback.into(), initial_value.into()], + &[callback.into(), initial_value.into_or_undefined()], context, ) } diff --git a/boa_engine/src/object/mod.rs b/boa_engine/src/object/mod.rs index 09735b9c733..1b5ab6597ee 100644 --- a/boa_engine/src/object/mod.rs +++ b/boa_engine/src/object/mod.rs @@ -40,7 +40,7 @@ use crate::{ typed_array::integer_indexed_object::IntegerIndexed, DataView, Date, RegExp, }, - context::StandardConstructor, + context::intrinsics::StandardConstructor, property::{Attribute, PropertyDescriptor, PropertyKey}, Context, JsBigInt, JsResult, JsString, JsSymbol, JsValue, }; @@ -1418,8 +1418,9 @@ impl<'context> FunctionBuilder<'context> { pub fn build(self) -> JsObject { let function = JsObject::from_proto_and_data( self.context - .standard_objects() - .function_object() + .intrinsics() + .standard_constructors() + .function() .prototype(), ObjectData::function(self.function), ); @@ -1437,7 +1438,13 @@ impl<'context> FunctionBuilder<'context> { pub(crate) fn build_function_prototype(self, object: &JsObject) { let mut object = object.borrow_mut(); object.data = ObjectData::function(self.function); - object.set_prototype(self.context.standard_objects().object_object().prototype()); + object.set_prototype( + self.context + .intrinsics() + .standard_constructors() + .object() + .prototype(), + ); let property = PropertyDescriptor::builder() .writable(false) @@ -1547,9 +1554,9 @@ impl<'context> ObjectInitializer<'context> { /// Builder for creating constructors objects, like `Array`. pub struct ConstructorBuilder<'context> { context: &'context mut Context, - constructor_function: NativeFunctionSignature, - constructor_object: JsObject, - constructor_has_prototype: bool, + function: NativeFunctionSignature, + object: JsObject, + has_prototype_property: bool, prototype: JsObject, name: JsString, length: usize, @@ -1564,8 +1571,8 @@ impl Debug for ConstructorBuilder<'_> { f.debug_struct("ConstructorBuilder") .field("name", &self.name) .field("length", &self.length) - .field("constructor", &self.constructor_object) - .field("constructor_has_prototype", &self.constructor_has_prototype) + .field("constructor", &self.object) + .field("constructor_has_prototype", &self.has_prototype_property) .field("prototype", &self.prototype) .field("inherit", &self.inherit) .field("callable", &self.callable) @@ -1577,11 +1584,11 @@ impl Debug for ConstructorBuilder<'_> { impl<'context> ConstructorBuilder<'context> { /// Create a new `ConstructorBuilder`. #[inline] - pub fn new(context: &'context mut Context, constructor: NativeFunctionSignature) -> Self { + pub fn new(context: &'context mut Context, function: NativeFunctionSignature) -> Self { Self { context, - constructor_function: constructor, - constructor_object: JsObject::empty(), + function, + object: JsObject::empty(), prototype: JsObject::empty(), length: 0, name: JsString::default(), @@ -1589,22 +1596,22 @@ impl<'context> ConstructorBuilder<'context> { constructor: true, inherit: None, custom_prototype: None, - constructor_has_prototype: true, + has_prototype_property: true, } } #[inline] - pub(crate) fn with_standard_object( + pub(crate) fn with_standard_constructor( context: &'context mut Context, - constructor: NativeFunctionSignature, - object: StandardConstructor, + function: NativeFunctionSignature, + standard_constructor: StandardConstructor, ) -> Self { Self { context, - constructor_function: constructor, - constructor_object: object.constructor, - constructor_has_prototype: true, - prototype: object.prototype, + function, + object: standard_constructor.constructor, + has_prototype_property: true, + prototype: standard_constructor.prototype, length: 0, name: JsString::default(), callable: true, @@ -1661,7 +1668,7 @@ impl<'context> ConstructorBuilder<'context> { .constructor(false) .build(); - self.constructor_object.borrow_mut().insert( + self.object.borrow_mut().insert( binding.binding, PropertyDescriptor::builder() .value(function) @@ -1700,7 +1707,7 @@ impl<'context> ConstructorBuilder<'context> { .writable(attribute.writable()) .enumerable(attribute.enumerable()) .configurable(attribute.configurable()); - self.constructor_object.borrow_mut().insert(key, property); + self.object.borrow_mut().insert(key, property); self } @@ -1742,7 +1749,7 @@ impl<'context> ConstructorBuilder<'context> { .maybe_set(set) .enumerable(attribute.enumerable()) .configurable(attribute.configurable()); - self.constructor_object.borrow_mut().insert(key, property); + self.object.borrow_mut().insert(key, property); self } @@ -1766,7 +1773,7 @@ impl<'context> ConstructorBuilder<'context> { P: Into, { let property = property.into(); - self.constructor_object.borrow_mut().insert(key, property); + self.object.borrow_mut().insert(key, property); self } @@ -1809,7 +1816,8 @@ impl<'context> ConstructorBuilder<'context> { self } - /// Specify the prototype this constructor object inherits from. + /// Specify the parent prototype which objects created by this constructor + /// inherit from. /// /// Default is `Object.prototype` #[inline] @@ -1818,7 +1826,7 @@ impl<'context> ConstructorBuilder<'context> { self } - /// Specify the __proto__ for this constructor. + /// Specify the `[[Prototype]]` internal field of this constructor. /// /// Default is `Function.prototype` #[inline] @@ -1831,8 +1839,8 @@ impl<'context> ConstructorBuilder<'context> { /// /// Default is `true` #[inline] - pub fn constructor_has_prototype(&mut self, constructor_has_prototype: bool) -> &mut Self { - self.constructor_has_prototype = constructor_has_prototype; + pub fn has_prototype_property(&mut self, has_prototype_property: bool) -> &mut Self { + self.has_prototype_property = has_prototype_property; self } @@ -1846,7 +1854,7 @@ impl<'context> ConstructorBuilder<'context> { pub fn build(&mut self) -> JsObject { // Create the native function let function = Function::Native { - function: self.constructor_function, + function: self.function, constructor: self.constructor, }; @@ -1862,7 +1870,7 @@ impl<'context> ConstructorBuilder<'context> { .configurable(true); { - let mut constructor = self.constructor_object.borrow_mut(); + let mut constructor = self.object.borrow_mut(); constructor.data = ObjectData::function(function); constructor.insert("length", length); constructor.insert("name", name); @@ -1872,13 +1880,14 @@ impl<'context> ConstructorBuilder<'context> { } else { constructor.set_prototype( self.context - .standard_objects() - .function_object() + .intrinsics() + .standard_constructors() + .function() .prototype(), ); } - if self.constructor_has_prototype { + if self.has_prototype_property { constructor.insert( PROTOTYPE, PropertyDescriptor::builder() @@ -1895,7 +1904,7 @@ impl<'context> ConstructorBuilder<'context> { prototype.insert( "constructor", PropertyDescriptor::builder() - .value(self.constructor_object.clone()) + .value(self.object.clone()) .writable(true) .enumerable(false) .configurable(true), @@ -1904,11 +1913,16 @@ impl<'context> ConstructorBuilder<'context> { if let Some(proto) = self.inherit.take() { prototype.set_prototype(proto); } else { - prototype - .set_prototype(self.context.standard_objects().object_object().prototype()); + prototype.set_prototype( + self.context + .intrinsics() + .standard_constructors() + .object() + .prototype(), + ); } } - self.constructor_object.clone() + self.object.clone() } } diff --git a/boa_engine/src/object/operations.rs b/boa_engine/src/object/operations.rs index 597df4d14c0..ee742010ce6 100644 --- a/boa_engine/src/object/operations.rs +++ b/boa_engine/src/object/operations.rs @@ -1,6 +1,6 @@ use crate::{ builtins::Array, - context::{StandardConstructor, StandardObjects}, + context::intrinsics::{StandardConstructor, StandardConstructors}, object::JsObject, property::{PropertyDescriptor, PropertyDescriptorBuilder, PropertyKey, PropertyNameKind}, symbol::WellKnownSymbols, @@ -473,7 +473,7 @@ impl JsObject { context: &mut Context, ) -> JsResult where - F: FnOnce(&StandardObjects) -> &StandardConstructor, + F: FnOnce(&StandardConstructors) -> &StandardConstructor, { // 1. Assert: Type(O) is Object. @@ -482,7 +482,9 @@ impl JsObject { // 3. If C is undefined, return defaultConstructor. if c.is_undefined() { - return Ok(default_constructor(context.standard_objects()).constructor()); + return Ok( + default_constructor(context.intrinsics().standard_constructors()).constructor(), + ); } // 4. If Type(C) is not Object, throw a TypeError exception. @@ -497,7 +499,9 @@ impl JsObject { // 6. If S is either undefined or null, return defaultConstructor. if s.is_null_or_undefined() { - return Ok(default_constructor(context.standard_objects()).constructor()); + return Ok( + default_constructor(context.intrinsics().standard_constructors()).constructor(), + ); } // 7. If IsConstructor(S) is true, return S. diff --git a/boa_engine/src/value/conversions.rs b/boa_engine/src/value/conversions.rs index 03ff1d85205..75fe285db83 100644 --- a/boa_engine/src/value/conversions.rs +++ b/boa_engine/src/value/conversions.rs @@ -134,15 +134,15 @@ impl From<()> for JsValue { } } -impl From> for JsValue +pub(crate) trait IntoOrUndefined { + fn into_or_undefined(self) -> JsValue; +} + +impl IntoOrUndefined for Option where - T: Into, + T: Into, { - #[inline] - fn from(value: Option) -> Self { - match value { - Some(value) => value.into(), - None => Self::undefined(), - } + fn into_or_undefined(self) -> JsValue { + self.map_or_else(JsValue::undefined, Into::into) } } diff --git a/boa_engine/src/value/mod.rs b/boa_engine/src/value/mod.rs index df3818a3b52..a3120dfbeca 100644 --- a/boa_engine/src/value/mod.rs +++ b/boa_engine/src/value/mod.rs @@ -465,28 +465,44 @@ impl JsValue { context.throw_type_error("cannot convert 'null' or 'undefined' to object") } JsValue::Boolean(boolean) => { - let prototype = context.standard_objects().boolean_object().prototype(); + let prototype = context + .intrinsics() + .standard_constructors() + .boolean() + .prototype(); Ok(JsObject::from_proto_and_data( prototype, ObjectData::boolean(*boolean), )) } JsValue::Integer(integer) => { - let prototype = context.standard_objects().number_object().prototype(); + let prototype = context + .intrinsics() + .standard_constructors() + .number() + .prototype(); Ok(JsObject::from_proto_and_data( prototype, ObjectData::number(f64::from(*integer)), )) } JsValue::Rational(rational) => { - let prototype = context.standard_objects().number_object().prototype(); + let prototype = context + .intrinsics() + .standard_constructors() + .number() + .prototype(); Ok(JsObject::from_proto_and_data( prototype, ObjectData::number(*rational), )) } JsValue::String(ref string) => { - let prototype = context.standard_objects().string_object().prototype(); + let prototype = context + .intrinsics() + .standard_constructors() + .string() + .prototype(); let object = JsObject::from_proto_and_data(prototype, ObjectData::string(string.clone())); @@ -502,14 +518,22 @@ impl JsValue { Ok(object) } JsValue::Symbol(ref symbol) => { - let prototype = context.standard_objects().symbol_object().prototype(); + let prototype = context + .intrinsics() + .standard_constructors() + .symbol() + .prototype(); Ok(JsObject::from_proto_and_data( prototype, ObjectData::symbol(symbol.clone()), )) } JsValue::BigInt(ref bigint) => { - let prototype = context.standard_objects().bigint_object().prototype(); + let prototype = context + .intrinsics() + .standard_constructors() + .bigint_object() + .prototype(); Ok(JsObject::from_proto_and_data( prototype, ObjectData::big_int(bigint.clone()), diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index 44e5646f4cf..0149fbf74be 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -10,7 +10,7 @@ use crate::{ }, generator::{Generator, GeneratorContext, GeneratorState}, }, - context::StandardObjects, + context::intrinsics::StandardConstructors, environments::{BindingLocator, DeclarativeEnvironmentStack}, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, property::PropertyDescriptor, @@ -403,7 +403,11 @@ impl ToInternedString for CodeBlock { pub(crate) fn create_function_object(code: Gc, context: &mut Context) -> JsObject { let _timer = Profiler::global().start_event("JsVmFunction::new", "vm"); - let function_prototype = context.standard_objects().function_object().prototype(); + let function_prototype = context + .intrinsics() + .standard_constructors() + .function() + .prototype(); let prototype = context.construct_object(); @@ -466,8 +470,9 @@ pub(crate) fn create_generator_function_object( context: &mut Context, ) -> JsObject { let function_prototype = context - .standard_objects() - .generator_function_object() + .intrinsics() + .standard_constructors() + .generator_function() .prototype(); let name_property = PropertyDescriptor::builder() @@ -485,7 +490,11 @@ pub(crate) fn create_generator_function_object( .build(); let prototype = JsObject::from_proto_and_data( - context.standard_objects().generator_object().prototype(), + context + .intrinsics() + .standard_constructors() + .generator() + .prototype(), ObjectData::ordinary(), ); @@ -790,7 +799,11 @@ impl JsObject { { prototype.clone() } else { - context.standard_objects().generator_object().prototype() + context + .intrinsics() + .standard_constructors() + .generator() + .prototype() }; let generator = Self::from_proto_and_data( @@ -867,7 +880,7 @@ impl JsObject { // see let prototype = get_prototype_from_constructor( this_target, - StandardObjects::object_object, + StandardConstructors::object, context, )?; Self::from_proto_and_data(prototype, ObjectData::ordinary()).into()