Skip to content

Commit

Permalink
Merge e18aa7d into ae73c26
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat committed Aug 28, 2021
2 parents ae73c26 + e18aa7d commit 802ffe3
Show file tree
Hide file tree
Showing 21 changed files with 1,327 additions and 632 deletions.
4 changes: 2 additions & 2 deletions boa/src/builtins/array/array_iterator.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
builtins::{function::make_builtin_fn, iterable::create_iter_result_object, Array, JsValue},
builtins::{iterable::create_iter_result_object, Array, JsValue},
gc::{Finalize, Trace},
object::{JsObject, ObjectData},
object::{function::make_builtin_fn, JsObject, ObjectData},
property::{PropertyDescriptor, PropertyNameKind},
symbol::WellKnownSymbols,
BoaProfiler, Context, JsResult,
Expand Down
276 changes: 4 additions & 272 deletions boa/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,284 +11,16 @@
//! [spec]: https://tc39.es/ecma262/#sec-function-objects
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function

use crate::object::PROTOTYPE;
use crate::{
builtins::{Array, BuiltIn},
environment::lexical_environment::Environment,
gc::{empty_trace, Finalize, Trace},
object::{ConstructorBuilder, FunctionBuilder, JsObject, Object, ObjectData},
property::{Attribute, PropertyDescriptor},
syntax::ast::node::{FormalParameter, RcStatementList},
builtins::BuiltIn,
object::{function::Function, ConstructorBuilder, FunctionBuilder, ObjectData, PROTOTYPE},
property::Attribute,
BoaProfiler, Context, JsResult, JsValue,
};
use bitflags::bitflags;
use dyn_clone::DynClone;
use sealed::Sealed;
use std::fmt::{self, Debug};

#[cfg(test)]
mod tests;

// Allows restricting closures to only `Copy` ones.
// Used the sealed pattern to disallow external implementations
// of `DynCopy`.
mod sealed {
pub trait Sealed {}
impl<T: Copy> Sealed for T {}
}
pub trait DynCopy: Sealed {}
impl<T: Copy> DynCopy for T {}

/// Type representing a native built-in function a.k.a. function pointer.
///
/// Native functions need to have this signature in order to
/// be callable from Javascript.
pub type NativeFunction = fn(&JsValue, &[JsValue], &mut Context) -> JsResult<JsValue>;

/// Trait representing a native built-in closure.
///
/// Closures need to have this signature in order to
/// be callable from Javascript, but most of the time the compiler
/// is smart enough to correctly infer the types.
pub trait ClosureFunction:
Fn(&JsValue, &[JsValue], &mut Context) -> JsResult<JsValue> + DynCopy + DynClone + 'static
{
}

// The `Copy` bound automatically infers `DynCopy` and `DynClone`
impl<T> ClosureFunction for T where
T: Fn(&JsValue, &[JsValue], &mut Context) -> JsResult<JsValue> + Copy + 'static
{
}

// Allows cloning Box<dyn ClosureFunction>
dyn_clone::clone_trait_object!(ClosureFunction);

#[derive(Clone, Copy, Finalize)]
pub struct BuiltInFunction(pub(crate) NativeFunction);

unsafe impl Trace for BuiltInFunction {
empty_trace!();
}

impl From<NativeFunction> for BuiltInFunction {
fn from(function: NativeFunction) -> Self {
Self(function)
}
}

impl Debug for BuiltInFunction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("[native]")
}
}

bitflags! {
#[derive(Finalize, Default)]
pub struct FunctionFlags: u8 {
const CONSTRUCTABLE = 0b0000_0010;
const LEXICAL_THIS_MODE = 0b0000_0100;
}
}

impl FunctionFlags {
#[inline]
pub(crate) fn is_constructable(&self) -> bool {
self.contains(Self::CONSTRUCTABLE)
}

#[inline]
pub(crate) fn is_lexical_this_mode(&self) -> bool {
self.contains(Self::LEXICAL_THIS_MODE)
}
}

unsafe impl Trace for FunctionFlags {
empty_trace!();
}

/// 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(Trace, Finalize)]
pub enum Function {
Native {
function: BuiltInFunction,
constructable: bool,
},
Closure {
#[unsafe_ignore_trace]
function: Box<dyn ClosureFunction>,
constructable: bool,
},
Ordinary {
flags: FunctionFlags,
body: RcStatementList,
params: Box<[FormalParameter]>,
environment: Environment,
},
}

impl Debug for Function {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Function {{ ... }}")
}
}

impl Function {
// Adds the final rest parameters to the Environment as an array
pub(crate) fn add_rest_param(
&self,
param: &FormalParameter,
index: usize,
args_list: &[JsValue],
context: &mut Context,
local_env: &Environment,
) {
// Create array of values
let array = Array::new_array(context);
Array::add_to_array_object(&array, args_list.get(index..).unwrap_or_default(), context)
.unwrap();

// Create binding
local_env
// Function parameters can share names in JavaScript...
.create_mutable_binding(param.name().to_owned(), false, true, context)
.expect("Failed to create binding for rest param");

// Set Binding to value
local_env
.initialize_binding(param.name(), array, context)
.expect("Failed to initialize rest param");
}

// Adds an argument to the environment
pub(crate) fn add_arguments_to_environment(
&self,
param: &FormalParameter,
value: JsValue,
local_env: &Environment,
context: &mut Context,
) {
// Create binding
local_env
.create_mutable_binding(param.name().to_owned(), false, true, context)
.expect("Failed to create binding");

// Set Binding to value
local_env
.initialize_binding(param.name(), value, context)
.expect("Failed to intialize binding");
}

/// Returns true if the function object is constructable.
pub fn is_constructable(&self) -> bool {
match self {
Self::Native { constructable, .. } => *constructable,
Self::Closure { constructable, .. } => *constructable,
Self::Ordinary { flags, .. } => flags.is_constructable(),
}
}
}

/// Arguments.
///
/// <https://tc39.es/ecma262/#sec-createunmappedargumentsobject>
pub fn create_unmapped_arguments_object(
arguments_list: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let len = arguments_list.len();
let obj = JsObject::new(Object::default());
// Set length
let length = PropertyDescriptor::builder()
.value(len)
.writable(true)
.enumerable(false)
.configurable(true);
// Define length as a property
crate::object::internal_methods::ordinary_define_own_property(
&obj,
"length".into(),
length.into(),
context,
)?;
let mut index: usize = 0;
while index < len {
let val = arguments_list.get(index).expect("Could not get argument");
let prop = PropertyDescriptor::builder()
.value(val.clone())
.writable(true)
.enumerable(true)
.configurable(true);

obj.insert(index, prop);
index += 1;
}

Ok(JsValue::new(obj))
}

/// Creates a new member function of a `Object` or `prototype`.
///
/// A function registered using this macro can then be called from Javascript using:
///
/// parent.name()
///
/// See the javascript 'Number.toString()' as an example.
///
/// # Arguments
/// function: The function to register as a built in function.
/// name: The name of the function (how it will be called but without the ()).
/// parent: The object to register the function on, if the global object is used then the function is instead called as name()
/// without requiring the parent, see parseInt() as an example.
/// length: As described at <https://tc39.es/ecma262/#sec-function-instances-length>, The value of the "length" property is an integer that
/// indicates the typical number of arguments expected by the function. However, the language permits the function to be invoked with
/// some other number of arguments.
///
/// If no length is provided, the length will be set to 0.
pub fn make_builtin_fn<N>(
function: NativeFunction,
name: N,
parent: &JsObject,
length: usize,
interpreter: &Context,
) where
N: Into<String>,
{
let name = name.into();
let _timer = BoaProfiler::global().start_event(&format!("make_builtin_fn: {}", &name), "init");

let mut function = Object::function(
Function::Native {
function: function.into(),
constructable: false,
},
interpreter
.standard_objects()
.function_object()
.prototype()
.into(),
);
let attribute = PropertyDescriptor::builder()
.writable(false)
.enumerable(false)
.configurable(true);
function.insert_property("length", attribute.clone().value(length));
function.insert_property("name", attribute.value(name.as_str()));

parent.clone().insert_property(
name,
PropertyDescriptor::builder()
.value(function)
.writable(true)
.enumerable(false)
.configurable(true),
);
}

#[derive(Debug, Clone, Copy)]
pub struct BuiltInFunctionObject;

Expand Down Expand Up @@ -316,7 +48,7 @@ impl BuiltInFunctionObject {
.set_prototype_instance(prototype.into());

this.set_data(ObjectData::function(Function::Native {
function: BuiltInFunction(|_, _, _| Ok(JsValue::undefined())),
function: |_, _, _| Ok(JsValue::undefined()),
constructable: true,
}));
Ok(this)
Expand Down
4 changes: 2 additions & 2 deletions boa/src/builtins/map/map_iterator.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
builtins::{function::make_builtin_fn, iterable::create_iter_result_object, Array, JsValue},
object::{JsObject, ObjectData},
builtins::{iterable::create_iter_result_object, Array, JsValue},
object::{function::make_builtin_fn, JsObject, ObjectData},
property::{PropertyDescriptor, PropertyNameKind},
symbol::WellKnownSymbols,
BoaProfiler, Context, JsResult,
Expand Down
3 changes: 1 addition & 2 deletions boa/src/builtins/number/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
//! [spec]: https://tc39.es/ecma262/#sec-number-object
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number

use super::function::make_builtin_fn;
use super::string::is_trimmable_whitespace;
use crate::{
builtins::BuiltIn,
object::{ConstructorBuilder, ObjectData, PROTOTYPE},
object::{function::make_builtin_fn, ConstructorBuilder, ObjectData, PROTOTYPE},
property::Attribute,
value::{AbstractRelation, IntegerOrInfinity, JsValue},
BoaProfiler, Context, JsResult,
Expand Down
4 changes: 2 additions & 2 deletions boa/src/builtins/object/for_in_iterator.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
builtins::{function::make_builtin_fn, iterable::create_iter_result_object},
builtins::iterable::create_iter_result_object,
gc::{Finalize, Trace},
object::{JsObject, ObjectData},
object::{function::make_builtin_fn, JsObject, ObjectData},
property::PropertyDescriptor,
property::PropertyKey,
symbol::WellKnownSymbols,
Expand Down
4 changes: 2 additions & 2 deletions boa/src/builtins/regexp/regexp_string_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
use regexp::{advance_string_index, RegExp};

use crate::{
builtins::{function::make_builtin_fn, iterable::create_iter_result_object, regexp},
builtins::{iterable::create_iter_result_object, regexp},
gc::{Finalize, Trace},
object::{JsObject, ObjectData},
object::{function::make_builtin_fn, JsObject, ObjectData},
property::PropertyDescriptor,
symbol::WellKnownSymbols,
BoaProfiler, Context, JsResult, JsString, JsValue,
Expand Down
3 changes: 1 addition & 2 deletions boa/src/builtins/set/set_iterator.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use crate::{
builtins::function::make_builtin_fn,
builtins::iterable::create_iter_result_object,
builtins::Array,
builtins::JsValue,
object::{JsObject, ObjectData},
object::{function::make_builtin_fn, JsObject, ObjectData},
property::{PropertyDescriptor, PropertyNameKind},
symbol::WellKnownSymbols,
BoaProfiler, Context, JsResult,
Expand Down
6 changes: 2 additions & 4 deletions boa/src/builtins/string/string_iterator.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use crate::{
builtins::{
function::make_builtin_fn, iterable::create_iter_result_object, string::code_point_at,
},
builtins::{iterable::create_iter_result_object, string::code_point_at},
gc::{Finalize, Trace},
object::{JsObject, ObjectData},
object::{function::make_builtin_fn, JsObject, ObjectData},
property::PropertyDescriptor,
symbol::WellKnownSymbols,
BoaProfiler, Context, JsResult, JsValue,
Expand Down

0 comments on commit 802ffe3

Please sign in to comment.