Skip to content

Commit

Permalink
FunctionKind has gone (not in spec anymore) symbol using new constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonwilliams committed Apr 25, 2020
1 parent 5dbcced commit 8e148cd
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 47 deletions.
125 changes: 95 additions & 30 deletions boa/src/builtins/function_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,7 @@ use std::fmt::{self, Debug};

/// _fn(this, arguments, ctx) -> ResultValue_ - The signature of a built-in function
pub type NativeFunctionData = fn(&Value, &[Value], &mut Interpreter) -> ResultValue;
/// Sets the functionKind
#[derive(Trace, Finalize, Debug, Clone)]
pub enum FunctionKind {
Normal,
ClassConstructor,
Generator,
Async,
AsyncGenerator,
NonConstructor,
}

/// Sets the ConstructorKind
#[derive(Debug, Copy, Clone)]
pub enum ConstructorKind {
Expand Down Expand Up @@ -67,18 +58,14 @@ pub struct Function {
pub internal_slots: Box<HashMap<String, Value>>,
/// Properties
pub properties: Box<HashMap<String, Property>>,
/// Function Kind
pub function_kind: FunctionKind,
/// is constructor??
pub is_constructor: bool,
/// Function Body
pub body: FunctionBody,
/// Formal Paramaters
pub params: Vec<FormalParameter>,
/// This Mode
pub this_mode: ThisMode,
// Environment
pub environment: Environment,
pub environment: Option<Environment>,
}

impl Function {
Expand All @@ -91,18 +78,40 @@ impl Function {
body: FunctionBody,
scope: Environment,
this_mode: ThisMode,
mut kind: FunctionKind,
) -> Function {
let needs_construct: bool;
match kind {
FunctionKind::Normal => needs_construct = true,
FunctionKind::NonConstructor => {
needs_construct = false;
kind = FunctionKind::Normal;
}
_ => needs_construct = false,
}
// Create length property and set it's value
let length_property = Property::new()
.writable(false)
.enumerable(false)
.configurable(true)
.value(to_value(parameter_list.len()));

let mut func = Function {
internal_slots: Box::new(HashMap::new()),
properties: Box::new(HashMap::new()),
body,
environment: Some(scope),
params: parameter_list,
this_mode,
};

func.set_internal_slot("extensible", to_value(true));
func.set_internal_slot(PROTOTYPE, to_value(proto.clone()));
func.set_internal_slot("home_object", to_value(undefined()));

func.define_own_property(String::from("length"), length_property);
func
}

/// This will create a built-in function object
///
/// <https://tc39.es/ecma262/#sec-createbuiltinfunction>
pub fn create_builtin(
proto: Value,
parameter_list: Vec<FormalParameter>,
body: FunctionBody,
this_mode: ThisMode,
) -> Function {
// Create length property and set it's value
let length_property = Property::new()
.writable(false)
Expand All @@ -113,15 +122,14 @@ impl Function {
let mut func = Function {
internal_slots: Box::new(HashMap::new()),
properties: Box::new(HashMap::new()),
function_kind: kind,
is_constructor: needs_construct,
body,
environment: scope,
environment: None,
params: parameter_list,
this_mode,
};

func.set_internal_slot("extensible", to_value(true));
// TODO: The below needs to be a property not internal slot
func.set_internal_slot(PROTOTYPE, to_value(proto.clone()));
func.set_internal_slot("home_object", to_value(undefined()));

Expand All @@ -141,8 +149,11 @@ impl Function {
) -> ResultValue {
// 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(this.clone(), undefined(), Some(self.environment.clone()));
let local_env = new_function_environment(
this.clone(),
undefined(),
Some(self.environment.as_ref().unwrap().clone()),
);

// Add argument bindings to the function environment
for i in 0..self.params.len() {
Expand Down Expand Up @@ -173,6 +184,60 @@ impl Function {
FunctionBody::Ordinary(ref body) => interpreter.run(body),
};

// local_env gets dropped here, its no longer needed
interpreter.realm.environment.pop();
result
}

/// This will handle calls for both ordinary and built-in functions
///
/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget>
pub fn construct(
&self,
this: &Value, // represents a pointer to this function object wrapped in a GC (not a `this` JS object)
new_target: Value, // new `this` value
args_list: &Vec<Value>,
interpreter: &mut Interpreter,
) -> ResultValue {
// 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>

// builtin constructs functions don't need a new env
let local_env = new_function_environment(
this.clone(),
new_target.clone(),
Some(self.environment.as_ref().unwrap().clone()),
);

// Add argument bindings to the function environment
for i in 0..self.params.len() {
let param = self.params.get(i).expect("Could not get param");
// Rest Parameters
if param.is_rest_param {
self.add_rest_param(param, i, args_list, interpreter, &local_env);
break;
}

let value = args_list.get(i).expect("Could not get value");
self.add_arguments_to_environment(param, value.clone(), &local_env);
}

// Add arguments object
let arguments_obj = create_unmapped_arguments_object(args_list);
local_env
.borrow_mut()
.create_mutable_binding("arguments".to_string(), false);
local_env
.borrow_mut()
.initialize_binding("arguments", arguments_obj);

interpreter.realm.environment.push(local_env);

let result = match self.body {
FunctionBody::BuiltIn(func) => func(&new_target, args_list, interpreter),
FunctionBody::Ordinary(ref body) => interpreter.run(body),
};

interpreter.realm.environment.pop();
result
}
Expand Down
23 changes: 12 additions & 11 deletions boa/src/builtins/symbol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod tests;

use crate::{
builtins::{
function_object::{Function, FunctionBody, ThisMode},
object::{
internal_methods_trait::ObjectInternalMethods, Object, ObjectKind, INSTANCE_PROTOTYPE,
PROTOTYPE,
Expand Down Expand Up @@ -57,24 +58,24 @@ pub fn to_string(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue

/// <https://tc39.es/ecma262/#sec-symbol-constructor>
pub fn create_constructor(global: &Value) -> Value {
// Create Symbol constructor (or function in Symbol's case)
let mut symbol_constructor = Object::default();
symbol_constructor.set_internal_method("call", call_symbol);
// symbol_constructor.set_internal_method("call", call_symbol);

// Create prototype
let mut symbol_prototype = Object::default();
let symbol_prototype = ValueData::new_obj(Some(&global));

// Create Symbol constructor (or function in Symbol's case)
let symbol_constructor = Function::create_builtin(
symbol_prototype.clone(),
vec![],
FunctionBody::BuiltIn(call_symbol),
ThisMode::NonLexical,
);

// Symbol.prototype[[Prototype]] points to Object.prototype
// Symbol Constructor -> Symbol Prototype -> Object Prototype
let object_prototype = global.get_field_slice("Object").get_field_slice(PROTOTYPE);
symbol_prototype.set_internal_slot(INSTANCE_PROTOTYPE, object_prototype);
symbol_prototype.set_method("toString", to_string);

let symbol_prototype_val = to_value(symbol_prototype);

let symbol_constructor_value = to_value(symbol_constructor);
symbol_prototype_val.set_field_slice("construcotor", symbol_constructor_value.clone());
symbol_constructor_value.set_field_slice(PROTOTYPE, symbol_prototype_val);
symbol_prototype.set_field_slice("constructor", symbol_constructor_value.clone());

symbol_constructor_value
}
14 changes: 8 additions & 6 deletions boa/src/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
builtins::{
array,
function::{create_unmapped_arguments_object, Function, RegularFunction},
function_object::{Function as FunctionObject, FunctionBody, FunctionKind, ThisMode},
function_object::{Function as FunctionObject, FunctionBody, ThisMode},
object::{
internal_methods_trait::ObjectInternalMethods, ObjectKind, INSTANCE_PROTOTYPE,
PROTOTYPE,
Expand Down Expand Up @@ -273,7 +273,6 @@ impl Executor for Interpreter {
FunctionBody::Ordinary(*expr.clone()),
self.realm.environment.get_current_environment().clone(),
ThisMode::Lexical,
FunctionKind::Normal,
);

let val = Gc::new(ValueData::FunctionObj(GcCell::new(func)));
Expand Down Expand Up @@ -418,9 +417,12 @@ impl Executor for Interpreter {
func_object.borrow().get_field_slice(PROTOTYPE),
);

let construct = func_object.get_internal_slot("construct");

match *construct {
match (*func_object).borrow() {
ValueData::FunctionObj(func) => {
func.borrow_mut()
.deref_mut()
.construct(&func_object, this, &v_args, self)
}
ValueData::Function(ref inner_func) => match inner_func.clone().into_inner() {
Function::NativeFunc(ref ntv) => {
let func = ntv.data;
Expand All @@ -433,7 +435,7 @@ impl Executor for Interpreter {
// Create new scope
let env = &mut self.realm.environment;
env.push(new_function_environment(
construct.clone(),
func_object.get_internal_slot("construct").clone(),
this,
Some(env.get_current_environment_ref().clone()),
));
Expand Down

0 comments on commit 8e148cd

Please sign in to comment.