From 257097b74f2890cb6dd0208a33123677d1bf1919 Mon Sep 17 00:00:00 2001 From: HalidOdat Date: Thu, 7 Apr 2022 20:45:56 +0200 Subject: [PATCH] Feature `JsFunction` --- boa_engine/src/builtins/array/mod.rs | 4 +- .../src/builtins/intl/date_time_format.rs | 10 ++-- boa_engine/src/class.rs | 14 ++--- boa_engine/src/object/jsarray.rs | 22 ++++---- boa_engine/src/object/jsfunction.rs | 56 +++++++++++++++++++ boa_engine/src/object/jstypedarray.rs | 23 ++++---- boa_engine/src/object/mod.rs | 18 +++--- 7 files changed, 105 insertions(+), 42 deletions(-) create mode 100644 boa_engine/src/object/jsfunction.rs diff --git a/boa_engine/src/builtins/array/mod.rs b/boa_engine/src/builtins/array/mod.rs index c31fd8f8a5b..7404a876cfb 100644 --- a/boa_engine/src/builtins/array/mod.rs +++ b/boa_engine/src/builtins/array/mod.rs @@ -25,7 +25,7 @@ use crate::{ context::intrinsics::StandardConstructors, object::{ internal_methods::get_prototype_from_constructor, ConstructorBuilder, FunctionBuilder, - JsObject, ObjectData, + JsFunction, JsObject, ObjectData, }, property::{Attribute, PropertyDescriptor, PropertyNameKind}, symbol::WellKnownSymbols, @@ -2857,7 +2857,7 @@ impl Array { } } - pub(crate) fn values_intrinsic(context: &mut Context) -> JsObject { + pub(crate) fn values_intrinsic(context: &mut Context) -> JsFunction { FunctionBuilder::native(context, Self::values) .name("values") .length(0) diff --git a/boa_engine/src/builtins/intl/date_time_format.rs b/boa_engine/src/builtins/intl/date_time_format.rs index 441e6c5bafe..b9ebee9e6e9 100644 --- a/boa_engine/src/builtins/intl/date_time_format.rs +++ b/boa_engine/src/builtins/intl/date_time_format.rs @@ -9,8 +9,10 @@ use crate::{ context::intrinsics::StandardConstructors, - object::internal_methods::get_prototype_from_constructor, - object::{ConstructorBuilder, JsObject, ObjectData}, + object::{ + internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsFunction, JsObject, + ObjectData, + }, Context, JsResult, JsString, JsValue, }; @@ -44,7 +46,7 @@ pub struct DateTimeFormat { impl DateTimeFormat { const NAME: &'static str = "DateTimeFormat"; - pub(super) fn init(context: &mut Context) -> JsObject { + pub(super) fn init(context: &mut Context) -> JsFunction { let _timer = Profiler::global().start_event(Self::NAME, "init"); ConstructorBuilder::new(context, Self::constructor) @@ -109,6 +111,6 @@ impl DateTimeFormat { // TODO b. Return ? ChainDateTimeFormat(dateTimeFormat, NewTarget, this). // 5. Return dateTimeFormat. - Ok(JsValue::Object(date_time_format)) + Ok(date_time_format.into()) } } diff --git a/boa_engine/src/class.rs b/boa_engine/src/class.rs index e61123d615c..94f81452692 100644 --- a/boa_engine/src/class.rs +++ b/boa_engine/src/class.rs @@ -63,7 +63,7 @@ use crate::{ builtins::function::NativeFunctionSignature, - object::{ConstructorBuilder, JsObject, NativeObject, ObjectData, PROTOTYPE}, + object::{ConstructorBuilder, JsFunction, JsObject, NativeObject, ObjectData, PROTOTYPE}, property::{Attribute, PropertyDescriptor, PropertyKey}, Context, JsResult, JsValue, }; @@ -168,8 +168,8 @@ impl<'context> ClassBuilder<'context> { } #[inline] - pub(crate) fn build(mut self) -> JsObject { - self.builder.build() + pub(crate) fn build(mut self) -> JsFunction { + JsFunction::from_object_unchecked(self.builder.build().into()) } /// Add a method to the class. @@ -239,8 +239,8 @@ impl<'context> ClassBuilder<'context> { pub fn accessor( &mut self, key: K, - get: Option, - set: Option, + get: Option, + set: Option, attribute: Attribute, ) -> &mut Self where @@ -257,8 +257,8 @@ impl<'context> ClassBuilder<'context> { pub fn static_accessor( &mut self, key: K, - get: Option, - set: Option, + get: Option, + set: Option, attribute: Attribute, ) -> &mut Self where diff --git a/boa_engine/src/object/jsarray.rs b/boa_engine/src/object/jsarray.rs index 1f69efdc738..4f1d0715bc7 100644 --- a/boa_engine/src/object/jsarray.rs +++ b/boa_engine/src/object/jsarray.rs @@ -1,6 +1,6 @@ use crate::{ builtins::Array, - object::{JsObject, JsObjectType}, + object::{JsFunction, JsObject, JsObjectType}, value::IntoOrUndefined, Context, JsResult, JsString, JsValue, }; @@ -34,9 +34,9 @@ impl JsArray { } } - /// Create an array from a `JsObject`, if the object is not an array throw a `TypeError`. + /// Create a [`JsArray`] from a [`JsObject`], if the object is not an array throw a `TypeError`. /// - /// This does not copy the fields of the array, it only does a shallow copy. + /// This does not clone the fields of the array, it only does a shallow clone of the object. #[inline] pub fn from_object(object: JsObject, context: &mut Context) -> JsResult { if object.borrow().is_array() { @@ -207,7 +207,7 @@ impl JsArray { #[inline] pub fn find( &self, - predicate: JsObject, + predicate: JsFunction, this_arg: Option, context: &mut Context, ) -> JsResult { @@ -221,7 +221,7 @@ impl JsArray { #[inline] pub fn filter( &self, - callback: JsObject, + callback: JsFunction, this_arg: Option, context: &mut Context, ) -> JsResult { @@ -240,7 +240,7 @@ impl JsArray { #[inline] pub fn map( &self, - callback: JsObject, + callback: JsFunction, this_arg: Option, context: &mut Context, ) -> JsResult { @@ -259,7 +259,7 @@ impl JsArray { #[inline] pub fn every( &self, - callback: JsObject, + callback: JsFunction, this_arg: Option, context: &mut Context, ) -> JsResult { @@ -277,7 +277,7 @@ impl JsArray { #[inline] pub fn some( &self, - callback: JsObject, + callback: JsFunction, this_arg: Option, context: &mut Context, ) -> JsResult { @@ -293,7 +293,7 @@ impl JsArray { } #[inline] - pub fn sort(&self, compare_fn: Option, context: &mut Context) -> JsResult { + pub fn sort(&self, compare_fn: Option, context: &mut Context) -> JsResult { Array::sort( &self.inner.clone().into(), &[compare_fn.into_or_undefined()], @@ -325,7 +325,7 @@ impl JsArray { #[inline] pub fn reduce( &self, - callback: JsObject, + callback: JsFunction, initial_value: Option, context: &mut Context, ) -> JsResult { @@ -339,7 +339,7 @@ impl JsArray { #[inline] pub fn reduce_right( &self, - callback: JsObject, + callback: JsFunction, initial_value: Option, context: &mut Context, ) -> JsResult { diff --git a/boa_engine/src/object/jsfunction.rs b/boa_engine/src/object/jsfunction.rs new file mode 100644 index 00000000000..70cca94d721 --- /dev/null +++ b/boa_engine/src/object/jsfunction.rs @@ -0,0 +1,56 @@ +use crate::{ + object::{JsObject, JsObjectType}, + Context, JsResult, JsValue, +}; +use boa_gc::{Finalize, Trace}; +use std::ops::Deref; + +/// JavaScript `Function` rust object. +#[derive(Debug, Clone, Trace, Finalize)] +pub struct JsFunction { + inner: JsObject, +} + +impl JsFunction { + #[inline] + pub(crate) fn from_object_unchecked(object: JsObject) -> Self { + Self { inner: object } + } + + /// Create a [`JsFunction`] from a [`JsObject`], if the object is not a function throw a `TypeError`. + /// + /// This does not clone the fields of the function, it only does a shallow clone of the object. + #[inline] + pub fn from_object(object: JsObject, context: &mut Context) -> JsResult { + if object.borrow().is_function() { + Ok(Self::from_object_unchecked(object)) + } else { + context.throw_type_error("object is not an Function") + } + } +} + +impl From for JsObject { + #[inline] + fn from(o: JsFunction) -> Self { + o.inner.clone() + } +} + +impl From for JsValue { + #[inline] + fn from(o: JsFunction) -> Self { + o.inner.clone().into() + } +} + +impl Deref for JsFunction { + type Target = JsObject; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl JsObjectType for JsFunction {} diff --git a/boa_engine/src/object/jstypedarray.rs b/boa_engine/src/object/jstypedarray.rs index 02b28e30109..c23bd04de40 100644 --- a/boa_engine/src/object/jstypedarray.rs +++ b/boa_engine/src/object/jstypedarray.rs @@ -1,6 +1,6 @@ use crate::{ builtins::typed_array::TypedArray, - object::{JsArray, JsObject, JsObjectType}, + object::{JsArray, JsFunction, JsObject, JsObjectType}, value::IntoOrUndefined, Context, JsResult, JsString, JsValue, }; @@ -14,6 +14,9 @@ pub struct JsTypedArray { } impl JsTypedArray { + /// Create a [`JsTypedArray`] from a [`JsObject`], if the object is not a typed array throw a `TypeError`. + /// + /// This does not clone the fields of the typed array, it only does a shallow clone of the object. #[inline] pub fn from_object(object: JsObject, context: &mut Context) -> JsResult { if object.borrow().is_typed_array() { @@ -21,7 +24,7 @@ impl JsTypedArray { inner: object.into(), }) } else { - context.throw_type_error("object is not an TypedArray") + context.throw_type_error("object is not a TypedArray") } } @@ -91,7 +94,7 @@ impl JsTypedArray { pub fn every( &self, - predicate: JsObject, + predicate: JsFunction, this_arg: Option, context: &mut Context, ) -> JsResult { @@ -109,7 +112,7 @@ impl JsTypedArray { #[inline] pub fn some( &self, - callback: JsObject, + callback: JsFunction, this_arg: Option, context: &mut Context, ) -> JsResult { @@ -125,7 +128,7 @@ impl JsTypedArray { } #[inline] - pub fn sort(&self, compare_fn: Option, context: &mut Context) -> JsResult { + pub fn sort(&self, compare_fn: Option, context: &mut Context) -> JsResult { TypedArray::sort(&self.inner, &[compare_fn.into_or_undefined()], context)?; Ok(self.clone()) @@ -134,7 +137,7 @@ impl JsTypedArray { #[inline] pub fn filter( &self, - callback: JsObject, + callback: JsFunction, this_arg: Option, context: &mut Context, ) -> JsResult { @@ -150,7 +153,7 @@ impl JsTypedArray { #[inline] pub fn map( &self, - callback: JsObject, + callback: JsFunction, this_arg: Option, context: &mut Context, ) -> JsResult { @@ -166,7 +169,7 @@ impl JsTypedArray { #[inline] pub fn reduce( &self, - callback: JsObject, + callback: JsFunction, initial_value: Option, context: &mut Context, ) -> JsResult { @@ -180,7 +183,7 @@ impl JsTypedArray { #[inline] pub fn reduce_right( &self, - callback: JsObject, + callback: JsFunction, initial_value: Option, context: &mut Context, ) -> JsResult { @@ -216,7 +219,7 @@ impl JsTypedArray { #[inline] pub fn find( &self, - predicate: JsObject, + predicate: JsFunction, this_arg: Option, context: &mut Context, ) -> JsResult { diff --git a/boa_engine/src/object/mod.rs b/boa_engine/src/object/mod.rs index 9e9fde976a1..5b524d9ec34 100644 --- a/boa_engine/src/object/mod.rs +++ b/boa_engine/src/object/mod.rs @@ -59,12 +59,14 @@ mod tests; pub(crate) mod internal_methods; mod jsarray; +mod jsfunction; mod jsobject; mod jstypedarray; mod operations; mod property_map; pub use jsarray::*; +pub use jsfunction::*; pub use jstypedarray::*; pub(crate) trait JsObjectType: @@ -1516,7 +1518,7 @@ impl<'context> FunctionBuilder<'context> { /// Build the function object. #[inline] - pub fn build(self) -> JsObject { + pub fn build(self) -> JsFunction { let function = JsObject::from_proto_and_data( self.context .intrinsics() @@ -1532,7 +1534,7 @@ impl<'context> FunctionBuilder<'context> { function.insert_property("length", property.clone().value(self.length)); function.insert_property("name", property.value(self.name)); - function + JsFunction::from_object_unchecked(function) } /// Initializes the `Function.prototype` function object. @@ -1817,8 +1819,8 @@ impl<'context> ConstructorBuilder<'context> { pub fn accessor( &mut self, key: K, - get: Option, - set: Option, + get: Option, + set: Option, attribute: Attribute, ) -> &mut Self where @@ -1838,8 +1840,8 @@ impl<'context> ConstructorBuilder<'context> { pub fn static_accessor( &mut self, key: K, - get: Option, - set: Option, + get: Option, + set: Option, attribute: Attribute, ) -> &mut Self where @@ -1952,7 +1954,7 @@ impl<'context> ConstructorBuilder<'context> { } /// Build the constructor function object. - pub fn build(&mut self) -> JsObject { + pub fn build(&mut self) -> JsFunction { // Create the native function let function = Function::Native { function: self.function, @@ -2024,6 +2026,6 @@ impl<'context> ConstructorBuilder<'context> { } } - self.object.clone() + JsFunction::from_object_unchecked(self.object.clone()) } }