@ -14,7 +14,7 @@
use crate ::{
builtins ::{
array ::Array ,
object ::{ Object , ObjectInternalMethods , ObjectKind , PROTOTYPE } ,
object ::{ Object , ObjectInternalMethods , ObjectKind , INSTANCE_PROTOTYPE , PROTOTYPE } ,
property ::Property ,
value ::{ ResultValue , Value } ,
} ,
@ -72,18 +72,6 @@ unsafe impl Trace for FunctionBody {
unsafe_empty_trace ! ( ) ;
}
/// Signal what sort of function this is
#[ derive(Clone, Debug, Copy, Finalize) ]
pub enum FunctionKind {
BuiltIn ,
Ordinary ,
}
/// Waiting on <https://github.com/Manishearth/rust-gc/issues/87> until we can derive Copy
unsafe impl Trace for FunctionKind {
unsafe_empty_trace ! ( ) ;
}
/// Boa representation of a Function Object.
///
/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects>
@ -95,48 +83,73 @@ pub struct Function {
pub params : Box < [ FormalParameter ] > ,
/// This Mode
pub this_mode : ThisMode ,
/// Function kind
pub kind : FunctionKind ,
// Environment, built-in functions don't need Environments
pub environment : Option < Environment > ,
/// Is it constructable
constructable : bool ,
/// Is it callable.
callable : bool ,
}
impl Function {
/// This will create an ordinary function object
///
/// <https://tc39.es/ecma262/#sec-ordinaryfunctioncreate>
pub fn create_ordinary < P > (
pub fn new < P > (
parameter_list : P ,
scope : Environment ,
scope : Option < Environment > ,
body : FunctionBody ,
this_mode : ThisMode ,
constructable : bool ,
callable : bool ,
) -> Self
where
P : Into < Box < [ FormalParameter ] > > ,
{
Self {
body ,
environment : Some ( scope ) ,
environment : scope ,
params : parameter_list . into ( ) ,
kind : FunctionKind ::Ordinary ,
this_mode ,
constructable ,
callable ,
}
}
/// This will create an ordinary function object
///
/// <https://tc39.es/ecma262/#sec-ordinaryfunctioncreate>
pub fn ordinary < P > (
parameter_list : P ,
scope : Environment ,
body : StatementList ,
this_mode : ThisMode ,
) -> Self
where
P : Into < Box < [ FormalParameter ] > > ,
{
Self ::new (
parameter_list . into ( ) ,
Some ( scope ) ,
FunctionBody ::Ordinary ( body ) ,
this_mode ,
true ,
true ,
)
}
/// This will create a built-in function object
///
/// <https://tc39.es/ecma262/#sec-createbuiltinfunction>
pub fn create_builtin < P > ( parameter_list : P , body : FunctionBody ) -> Self
pub fn builtin < P > ( parameter_list : P , body : NativeFunctionData ) -> Self
where
P : Into < Box < [ FormalParameter ] > > ,
{
Self {
body ,
params : parameter_list . into ( ) ,
this_mode : ThisMode ::NonLexical ,
kind : FunctionKind ::BuiltIn ,
environment : None ,
}
Self ::new (
parameter_list . into ( ) ,
None ,
FunctionBody ::BuiltIn ( body ) ,
ThisMode ::NonLexical ,
false ,
true ,
)
}
/// This will handle calls for both ordinary and built-in functions
@ -150,14 +163,10 @@ impl Function {
interpreter : & mut Interpreter ,
this_obj : & mut Value ,
) -> ResultValue {
match self . kind {
FunctionKind ::BuiltIn = > match & self . body {
if self . callable {
match self . body {
FunctionBody ::BuiltIn ( func ) = > func ( this_obj , args_list , interpreter ) ,
FunctionBody ::Ordinary ( _ ) = > {
panic! ( "Builtin function should not have Ordinary Function body" )
}
} ,
FunctionKind ::Ordinary = > {
FunctionBody ::Ordinary ( ref body ) = > {
// Create a new Function environment who's parent is set to the scope of the function declaration (self.environment)
// <https://tc39.es/ecma262/#sec-prepareforordinarycall>
let local_env = new_function_environment (
@ -192,16 +201,16 @@ impl Function {
interpreter . realm . environment . push ( local_env ) ;
// Call body should be set before reaching here
let result = match & self . body {
FunctionBody ::Ordinary ( ref body ) = > body . run ( interpreter ) ,
_ = > panic! ( "Ordinary function should not have BuiltIn Function body" ) ,
} ;
let result = body . run ( interpreter ) ;
// local_env gets dropped here, its no longer needed
interpreter . realm . environment . pop ( ) ;
result
}
}
} else {
panic! ( "TypeError: class constructors must be invoked with 'new'" ) ;
}
}
/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget>
@ -212,17 +221,13 @@ impl Function {
interpreter : & mut Interpreter ,
this_obj : & mut Value ,
) -> ResultValue {
match self . kind {
FunctionKind ::BuiltIn = > match & self . body {
if self . constructable {
match self . body {
FunctionBody ::BuiltIn ( func ) = > {
func ( this_obj , args_list , interpreter ) . unwrap ( ) ;
Ok ( this_obj . clone ( ) )
}
FunctionBody ::Ordinary ( _ ) = > {
panic! ( "Builtin function should not have Ordinary Function body" )
}
} ,
FunctionKind ::Ordinary = > {
FunctionBody ::Ordinary ( ref body ) = > {
// Create a new Function environment who's parent is set to the scope of the function declaration (self.environment)
// <https://tc39.es/ecma262/#sec-prepareforordinarycall>
let local_env = new_function_environment (
@ -256,16 +261,17 @@ impl Function {
interpreter . realm . environment . push ( local_env ) ;
// Call body should be set before reaching here
let _ = match & self . body {
FunctionBody ::Ordinary ( ref body ) = > body . run ( interpreter ) ,
_ = > panic! ( "Ordinary function should not have BuiltIn Function body" ) ,
} ;
let _ = body . run ( interpreter ) ;
// local_env gets dropped here, its no longer needed
let binding = interpreter . realm . environment . get_this_binding ( ) ;
Ok ( binding )
}
}
} else {
let name = this . get_field ( "name" ) . to_string ( ) ;
panic! ( "TypeError: {} is not a constructor" , name ) ;
}
}
// Adds the final rest parameters to the Environment as an array
@ -309,6 +315,16 @@ impl Function {
. borrow_mut ( )
. initialize_binding ( param . name ( ) , value ) ;
}
/// Returns true if the function object is callable.
pub fn is_callable ( & self ) -> bool {
self . callable
}
/// Returns true if the function object is constructable.
pub fn is_constructable ( & self ) -> bool {
self . constructable
}
}
impl Debug for Function {
@ -319,16 +335,6 @@ impl Debug for Function {
}
}
/// Function Prototype.
///
/// <https://tc39.es/ecma262/#sec-properties-of-the-function-prototype-object>
pub fn create_function_prototype ( ) {
let mut function_prototype : Object = Object ::default ( ) ;
// Set Kind to function (for historical & compatibility reasons)
// <https://tc39.es/ecma262/#sec-properties-of-the-function-prototype-object>
function_prototype . kind = ObjectKind ::Function ;
}
/// Arguments.
///
/// <https://tc39.es/ecma262/#sec-createunmappedargumentsobject>
@ -369,19 +375,25 @@ pub fn make_function(this: &mut Value, _: &[Value], _: &mut Interpreter) -> Resu
pub fn create ( global : & Value ) -> Value {
let prototype = Value ::new_object ( Some ( global ) ) ;
make_constructor_fn ( make_function , global , prototype )
make_constructor_fn ( "Function" , 1 , make_function , global , prototype , tru e )
}
/// Creates a new constructor function
///
/// This utility function handling linking the new Constructor to the prototype.
/// So far this is only used by internal functions
pub fn make_constructor_fn ( body : NativeFunctionData , global : & Value , proto : Value ) -> Value {
pub fn make_constructor_fn (
name : & str ,
length : i32 ,
body : NativeFunctionData ,
global : & Value ,
proto : Value ,
constructable : bool ,
) -> Value {
// Create the native function
let constructor_fn = crate ::builtins ::function ::Function ::create_builtin (
vec! [ ] ,
crate ::builtins ::function ::FunctionBody ::BuiltIn ( body ) ,
) ;
let mut constructor_fn = Function ::builtin ( Vec ::new ( ) , body ) ;
constructor_fn . constructable = constructable ;
// Get reference to Function.prototype
let func_prototype = global . get_field ( "Function" ) . get_field ( PROTOTYPE ) ;
@ -390,13 +402,27 @@ pub fn make_constructor_fn(body: NativeFunctionData, global: &Value, proto: Valu
let mut constructor_obj = Object ::function ( ) ;
constructor_obj . set_func ( constructor_fn ) ;
constructor_obj . set_internal_slot ( "__proto__" , func_prototype ) ;
constructor_obj . set_internal_slot ( INSTANCE_PROTOTYPE , func_prototype ) ;
let constructor_val = Value ::from ( constructor_obj ) ;
// Set proto.constructor -> constructor_obj
proto . set_field ( "constructor" , constructor_val . clone ( ) ) ;
constructor_val . set_field ( PROTOTYPE , proto ) ;
let length = Property ::new ( )
. value ( Value ::from ( length ) )
. writable ( false )
. configurable ( false )
. enumerable ( false ) ;
constructor_val . set_property_slice ( "length" , length ) ;
let name = Property ::new ( )
. value ( Value ::from ( name ) )
. writable ( false )
. configurable ( false )
. enumerable ( false ) ;
constructor_val . set_property_slice ( "name" , name ) ;
constructor_val
}
@ -407,7 +433,7 @@ pub fn make_builtin_fn<N>(function: NativeFunctionData, name: N, parent: &Value,
where
N : Into < String > ,
{
let func = Function ::create_ builtin( vec! [ ] , FunctionBody ::BuiltIn ( function ) ) ;
let func = Function ::builtin ( Vec ::new ( ) , function ) ;
let mut new_func = Object ::function ( ) ;
new_func . set_func ( func ) ;