Skip to content

Commit

Permalink
Add intrinsics reference to all functions
Browse files Browse the repository at this point in the history
  • Loading branch information
jedel1043 committed Apr 5, 2023
1 parent 2d77af8 commit 45dbf6e
Show file tree
Hide file tree
Showing 27 changed files with 396 additions and 261 deletions.
14 changes: 9 additions & 5 deletions boa_engine/src/builtins/error/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
use crate::{
builtins::{
function::Function, BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject,
function::{Function, FunctionKind},
BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject,
},
context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
error::JsNativeError,
Expand Down Expand Up @@ -124,10 +125,13 @@ impl IntrinsicObject for ThrowTypeError {

let mut obj = obj.borrow_mut();

obj.data = ObjectData::function(Function::Native {
function: NativeFunction::from_fn_ptr(throw_type_error),
constructor: None,
});
obj.data = ObjectData::function(Function::new(
FunctionKind::Native {
function: NativeFunction::from_fn_ptr(throw_type_error),
constructor: None,
},
intrinsics.clone(),
));
}

fn get(intrinsics: &Intrinsics) -> JsObject {
Expand Down
154 changes: 103 additions & 51 deletions boa_engine/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,8 @@ unsafe impl Trace for ClassFieldDefinition {
}}
}

/// Boa representation of a Function Object.
///
/// `FunctionBody` is specific to this interpreter, it will either be Rust code or JavaScript code
/// (AST Node).
///
/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects>
#[derive(Finalize)]
pub enum Function {
pub(crate) enum FunctionKind {
/// A rust function.
Native {
/// The rust function.
Expand Down Expand Up @@ -231,7 +225,34 @@ pub enum Function {
},
}

unsafe impl Trace for Function {
impl fmt::Debug for FunctionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FunctionKind::Native {
function,
constructor,
} => f
.debug_struct("FunctionKind::Native")
.field("function", &function)
.field("constructor", &constructor)
.finish(),
FunctionKind::Ordinary { .. } => f
.debug_struct("FunctionKind::Ordinary")
.finish_non_exhaustive(),
FunctionKind::Async { .. } => f
.debug_struct("FunctionKind::Async")
.finish_non_exhaustive(),
FunctionKind::Generator { .. } => f
.debug_struct("FunctionKind::Generator")
.finish_non_exhaustive(),
FunctionKind::AsyncGenerator { .. } => f
.debug_struct("FunctionKind::AsyncGenerator")
.finish_non_exhaustive(),
}
}
}

unsafe impl Trace for FunctionKind {
custom_trace! {this, {
match this {
Self::Native { function, .. } => {mark(function)}
Expand Down Expand Up @@ -265,27 +286,43 @@ unsafe impl Trace for Function {
}}
}

impl fmt::Debug for Function {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Function {{ ... }}")
}
/// Boa representation of a Function Object.
///
/// `FunctionBody` is specific to this interpreter, it will either be Rust code or JavaScript code
/// (AST Node).
///
/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects>
#[derive(Debug, Trace, Finalize)]
pub struct Function {
kind: FunctionKind,
realm_intrinsics: Intrinsics,
}

impl Function {
/// Returns true if the function object is a constructor.
pub fn is_constructor(&self) -> bool {
match self {
Self::Native { constructor, .. } => constructor.is_some(),
Self::Generator { .. } | Self::AsyncGenerator { .. } | Self::Async { .. } => false,
Self::Ordinary { code, .. } => !(code.this_mode == ThisMode::Lexical),
match &self.kind {
FunctionKind::Native { constructor, .. } => constructor.is_some(),
FunctionKind::Generator { .. }
| FunctionKind::AsyncGenerator { .. }
| FunctionKind::Async { .. } => false,
FunctionKind::Ordinary { code, .. } => !(code.this_mode == ThisMode::Lexical),
}
}

/// Creates a new `Function`.
pub(crate) fn new(kind: FunctionKind, intrinsics: Intrinsics) -> Self {
Self {
kind,
realm_intrinsics: intrinsics,
}
}

/// Returns true if the function object is a derived constructor.
pub(crate) const fn is_derived_constructor(&self) -> bool {
if let Self::Ordinary {
if let FunctionKind::Ordinary {
constructor_kind, ..
} = self
} = self.kind
{
constructor_kind.is_derived()
} else {
Expand All @@ -295,7 +332,7 @@ impl Function {

/// Returns the `[[ClassFieldInitializerName]]` internal slot of the function.
pub(crate) fn class_field_initializer_name(&self) -> Option<Sym> {
if let Self::Ordinary { code, .. } = self {
if let FunctionKind::Ordinary { code, .. } = &self.kind {
code.class_field_initializer_name
} else {
None
Expand All @@ -304,29 +341,29 @@ impl Function {

/// Returns a reference to the function `[[HomeObject]]` slot if present.
pub(crate) const fn get_home_object(&self) -> Option<&JsObject> {
match self {
Self::Ordinary { home_object, .. }
| Self::Async { home_object, .. }
| Self::Generator { home_object, .. }
| Self::AsyncGenerator { home_object, .. } => home_object.as_ref(),
Self::Native { .. } => None,
match &self.kind {
FunctionKind::Ordinary { home_object, .. }
| FunctionKind::Async { home_object, .. }
| FunctionKind::Generator { home_object, .. }
| FunctionKind::AsyncGenerator { home_object, .. } => home_object.as_ref(),
FunctionKind::Native { .. } => None,
}
}

/// Sets the `[[HomeObject]]` slot if present.
pub(crate) fn set_home_object(&mut self, object: JsObject) {
match self {
Self::Ordinary { home_object, .. }
| Self::Async { home_object, .. }
| Self::Generator { home_object, .. }
| Self::AsyncGenerator { home_object, .. } => *home_object = Some(object),
Self::Native { .. } => {}
match &mut self.kind {
FunctionKind::Ordinary { home_object, .. }
| FunctionKind::Async { home_object, .. }
| FunctionKind::Generator { home_object, .. }
| FunctionKind::AsyncGenerator { home_object, .. } => *home_object = Some(object),
FunctionKind::Native { .. } => {}
}
}

/// Returns the values of the `[[Fields]]` internal slot.
pub(crate) fn get_fields(&self) -> &[ClassFieldDefinition] {
if let Self::Ordinary { fields, .. } = self {
if let FunctionKind::Ordinary { fields, .. } = &self.kind {
fields
} else {
&[]
Expand All @@ -335,23 +372,23 @@ impl Function {

/// Pushes a value to the `[[Fields]]` internal slot if present.
pub(crate) fn push_field(&mut self, key: PropertyKey, value: JsFunction) {
if let Self::Ordinary { fields, .. } = self {
if let FunctionKind::Ordinary { fields, .. } = &mut self.kind {
fields.push(ClassFieldDefinition::Public(key, value));
}
}

/// Pushes a private value to the `[[Fields]]` internal slot if present.
pub(crate) fn push_field_private(&mut self, key: PrivateName, value: JsFunction) {
if let Self::Ordinary { fields, .. } = self {
if let FunctionKind::Ordinary { fields, .. } = &mut self.kind {
fields.push(ClassFieldDefinition::Private(key, value));
}
}

/// Returns the values of the `[[PrivateMethods]]` internal slot.
pub(crate) fn get_private_methods(&self) -> &[(PrivateName, PrivateElement)] {
if let Self::Ordinary {
if let FunctionKind::Ordinary {
private_methods, ..
} = self
} = &self.kind
{
private_methods
} else {
Expand All @@ -361,19 +398,19 @@ impl Function {

/// Pushes a private method to the `[[PrivateMethods]]` internal slot if present.
pub(crate) fn push_private_method(&mut self, name: PrivateName, method: PrivateElement) {
if let Self::Ordinary {
if let FunctionKind::Ordinary {
private_methods, ..
} = self
} = &mut self.kind
{
private_methods.push((name, method));
}
}

/// Returns the promise capability if the function is an async function.
pub(crate) const fn get_promise_capability(&self) -> Option<&PromiseCapability> {
if let Self::Async {
if let FunctionKind::Async {
promise_capability, ..
} = self
} = &self.kind
{
Some(promise_capability)
} else {
Expand All @@ -383,14 +420,29 @@ impl Function {

/// Sets the class object.
pub(crate) fn set_class_object(&mut self, object: JsObject) {
match self {
Self::Ordinary { class_object, .. }
| Self::Async { class_object, .. }
| Self::Generator { class_object, .. }
| Self::AsyncGenerator { class_object, .. } => *class_object = Some(object),
Self::Native { .. } => {}
match &mut self.kind {
FunctionKind::Ordinary { class_object, .. }
| FunctionKind::Async { class_object, .. }
| FunctionKind::Generator { class_object, .. }
| FunctionKind::AsyncGenerator { class_object, .. } => *class_object = Some(object),
FunctionKind::Native { .. } => {}
}
}

/// Gets the `Realm`'s intrinsic objects from where this function originates.
pub const fn realm_intrinsics(&self) -> &Intrinsics {
&self.realm_intrinsics
}

/// Gets a reference to the [`FunctionKind`] of the `Function`.
pub(crate) const fn kind(&self) -> &FunctionKind {
&self.kind
}

/// Gets a mutable reference to the [`FunctionKind`] of the `Function`.
pub(crate) fn kind_mut(&mut self) -> &mut FunctionKind {
&mut self.kind
}
}

/// The internal representation of a `Function` object.
Expand Down Expand Up @@ -854,17 +906,17 @@ impl BuiltInFunctionObject {
.filter(|n| !n.is_empty())
.unwrap_or_else(|| "anonymous".into());

match function {
Function::Native { .. } | Function::Ordinary { .. } => {
match function.kind {
FunctionKind::Native { .. } | FunctionKind::Ordinary { .. } => {
Ok(js_string!(utf16!("[Function: "), &name, utf16!("]")).into())
}
Function::Async { .. } => {
FunctionKind::Async { .. } => {
Ok(js_string!(utf16!("[AsyncFunction: "), &name, utf16!("]")).into())
}
Function::Generator { .. } => {
FunctionKind::Generator { .. } => {
Ok(js_string!(utf16!("[GeneratorFunction: "), &name, utf16!("]")).into())
}
Function::AsyncGenerator { .. } => {
FunctionKind::AsyncGenerator { .. } => {
Ok(js_string!(utf16!("[AsyncGeneratorFunction: "), &name, utf16!("]")).into())
}
}
Expand Down
3 changes: 2 additions & 1 deletion boa_engine/src/builtins/function/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ fn closure_capture_clone() {
.name("closure")
.build();

ctx.register_global_property("closure", func, Attribute::default()).unwrap();
ctx.register_global_property("closure", func, Attribute::default())
.unwrap();
}),
TestAction::assert_eq("closure()", "Hello world!"),
]);
Expand Down
2 changes: 1 addition & 1 deletion boa_engine/src/builtins/iterable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ macro_rules! if_abrupt_close_iterator {
pub(crate) use if_abrupt_close_iterator;

/// The built-in iterator prototypes.
#[derive(Debug, Default)]
#[derive(Debug, Default, Trace, Finalize)]
pub struct IteratorPrototypes {
/// The `IteratorPrototype` object.
iterator: JsObject,
Expand Down
15 changes: 11 additions & 4 deletions boa_engine/src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ struct Callable<Kind> {
name: JsString,
length: usize,
kind: Kind,
intrinsics: Intrinsics,
}

/// Marker for an ordinary object.
Expand Down Expand Up @@ -461,10 +462,13 @@ impl<S: ApplyToObject + IsConstructor> ApplyToObject for Callable<S> {
fn apply_to(self, object: &JsObject) {
self.kind.apply_to(object);

let function = function::Function::Native {
function: NativeFunction::from_fn_ptr(self.function),
constructor: S::IS_CONSTRUCTOR.then_some(function::ConstructorKind::Base),
};
let function = function::Function::new(
function::FunctionKind::Native {
function: NativeFunction::from_fn_ptr(self.function),
constructor: S::IS_CONSTRUCTOR.then_some(function::ConstructorKind::Base),
},
self.intrinsics,
);

let length = PropertyDescriptor::builder()
.value(self.length)
Expand Down Expand Up @@ -550,6 +554,7 @@ impl<'ctx> BuiltInBuilder<'ctx, OrdinaryObject> {
name: js_string!(""),
length: 0,
kind: OrdinaryFunction,
intrinsics: self.intrinsics.clone(),
},
prototype: self.intrinsics.constructors().function().prototype(),
}
Expand All @@ -573,6 +578,7 @@ impl<'ctx> BuiltInBuilder<'ctx, Callable<Constructor>> {
inherits: Some(intrinsics.constructors().object().prototype()),
attributes: Attribute::WRITABLE | Attribute::CONFIGURABLE,
},
intrinsics: intrinsics.clone(),
},
prototype: intrinsics.constructors().function().prototype(),
}
Expand All @@ -587,6 +593,7 @@ impl<'ctx> BuiltInBuilder<'ctx, Callable<Constructor>> {
name: self.kind.name,
length: self.kind.length,
kind: ConstructorNoProto,
intrinsics: self.intrinsics.clone(),
},
prototype: self.prototype,
}
Expand Down
Loading

0 comments on commit 45dbf6e

Please sign in to comment.