diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 3e1c6729ee6..8d2227e301d 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -47,6 +47,9 @@ mod tests; /// Static `prototype`, usually set on constructors as a key to point to their respective prototype object. pub static PROTOTYPE: &str = "prototype"; +/// This trait allows Rust types to be passed around as objects. +/// +/// This is automatically implemented, when a type implements `Debug`, `Any` and `Trace`. pub trait NativeObject: Debug + Any + Trace { fn as_any(&self) -> &dyn Any; fn as_mut_any(&mut self) -> &mut dyn Any; @@ -62,13 +65,32 @@ impl NativeObject for T { } } -pub trait Class: NativeObject { +/// Native class. +pub trait Class: NativeObject + Sized { /// The binding name of the object. const NAME: &'static str; - /// The amount of arguments the class `constructor` takes. + /// The amount of arguments the class `constructor` takes, default is `0`. const LENGTH: usize = 0; + /// The attibutes the class will be binded with, default is `writable`, `enumerable`, `configurable`. + const ATTRIBUTE: Attribute = Attribute::ALL; + + /// The constructor of the class. + fn constructor(this: &Value, args: &[Value], ctx: &mut Interpreter) -> Result; + + /// Initializes the internals and the methods of the class. + fn methods(class: &mut ClassBuilder<'_>) -> Result<()>; +} + +/// This is a wrapper around `Class::constructor` that sets the internal data of a class. +/// +/// This is automatically implemented, when a type implements `Class`. +pub trait ClassConstructor: Class { + fn raw_constructor(this: &Value, args: &[Value], ctx: &mut Interpreter) -> Result + where + Self: Sized; +} - /// This is a wrapper around `Self::constructor` that sets the internal data of the class. +impl ClassConstructor for T { fn raw_constructor(this: &Value, args: &[Value], ctx: &mut Interpreter) -> Result where Self: Sized, @@ -77,14 +99,6 @@ pub trait Class: NativeObject { this.set_data(ObjectData::NativeObject(Box::new(object_instance))); Ok(this.clone()) } - - /// The constructor of the class. - fn constructor(this: &Value, args: &[Value], ctx: &mut Interpreter) -> Result - where - Self: Sized; - - /// Initializes the internals and the methods of the class. - fn methods(class: &mut ClassBuilder<'_>) -> Result<()>; } /// Class builder which allows adding methods and static methods to the class. @@ -98,7 +112,7 @@ pub struct ClassBuilder<'context> { impl<'context> ClassBuilder<'context> { pub(crate) fn new(context: &'context mut Interpreter) -> Self where - T: Class, + T: ClassConstructor, { let global = context.global(); diff --git a/boa/src/builtins/property/attribute/mod.rs b/boa/src/builtins/property/attribute/mod.rs index e909a38ad7c..6261b0b48a7 100644 --- a/boa/src/builtins/property/attribute/mod.rs +++ b/boa/src/builtins/property/attribute/mod.rs @@ -20,6 +20,9 @@ bitflags! { /// None of the flags are present. const NONE = 0b0000_0000; + /// All the flags set (`WRITABLE`, `ENUMERABLE`, `CONFIGURABLE`). + const ALL = 0b0011_1111; + /// The `Writable` attribute decides whether the value associated with the property can be changed or not, from its initial value. const WRITABLE = 0b0000_0011; @@ -46,6 +49,7 @@ bitflags! { /// Is the `Configurable` flag defined. const HAS_CONFIGURABLE = 0b0010_0000; + } } diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 9a7b69c629f..dae773321cc 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -27,7 +27,7 @@ use crate::{ builtins::{ function::{Function, FunctionFlags, NativeFunction}, object::{Class, ClassBuilder, GcObject, Object, ObjectData, PROTOTYPE}, - property::PropertyKey, + property::{Property, PropertyKey}, value::{PreferredType, Type, Value}, Console, }, @@ -367,7 +367,11 @@ impl Interpreter { T::methods(&mut class_builder)?; let class = class_builder.build(); - self.global().set_field(T::NAME, class); + let property = Property::data_descriptor(class.into(), T::ATTRIBUTE); + self.global() + .as_object_mut() + .unwrap() + .insert_property(T::NAME, property); Ok(()) } }