Skip to content

Commit

Permalink
get/set environment
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonwilliams committed Apr 20, 2020
1 parent a271e6b commit f959e1e
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 8 deletions.
46 changes: 41 additions & 5 deletions boa/src/builtins/function_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ pub enum ConstructorKind {
#[derive(Debug, Copy, Clone)]
pub enum ThisMode {
Lexical,
Strict,
Global,
NonLexical,
}

/// FunctionBody is Boa specific, it will either be Rust code or JavaScript code (Block Node)
Expand Down Expand Up @@ -68,8 +67,8 @@ pub struct Function {
pub params: Vec<FormalParameter>,
/// This Mode
pub this_mode: ThisMode,
/// Reference to the current Environment Record
pub environment: Environment,
// Environment
pub environment: Option<Environment>,
}

impl Function {
Expand Down Expand Up @@ -108,7 +107,7 @@ impl Function {
function_kind: kind,
is_constructor: needs_construct,
body,
environment: realm.environment.get_current_environment().clone(),
environment: None,
params: parameter_list,
this_mode,
};
Expand All @@ -120,6 +119,43 @@ impl Function {
func.define_own_property(String::from("length"), length_property);
func
}

/// Sets the current environment on this function object
///
/// This should be set after creating struct instance.
/// Environment can't be an internal slot due to it not being a JSValue
pub fn set_environment(&mut self, env: Environment) {
self.environment = Some(env);
}

/// Fetches the current environment on this function.
///
/// The environment should be a Function Declarative Record
///
/// It should exist, if not it will panic
pub fn get_environment(&self) -> Environment {
match self.environment {
Some(v) => v,
None => panic!("No environment set on Function!"),
}
}

/// This will handle calls for both ordinary and built-in functions
///
/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist>
pub fn call(
&self,
this: &Value,
args_list: &Vec<Value>,
interpreter: &mut Interpreter,
) -> ResultValue {
// Is this a built-in function?
if let FunctionBody::BuiltIn(func) = self.body {
return func(this, args_list, interpreter);
}

Ok(undefined())
}
}

unsafe impl gc::Trace for Function {
Expand Down
37 changes: 34 additions & 3 deletions boa/src/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{
builtins::{
array,
function::{create_unmapped_arguments_object, Function, RegularFunction},
function_object::{Function as FunctionObject, FunctionBody, FunctionKind, ThisMode},
object::{
internal_methods_trait::ObjectInternalMethods, ObjectKind, INSTANCE_PROTOTYPE,
PROTOTYPE,
Expand Down Expand Up @@ -256,20 +257,50 @@ impl Executor for Interpreter {
Ok(array)
}
Node::FunctionDecl(ref name, ref args, ref expr) => {
let function =
Function::RegularFunc(RegularFunction::new(*expr.clone(), args.to_vec()));
let val = Gc::new(ValueData::Function(Box::new(GcCell::new(function))));
// Todo: Function.prototype doesn't exist yet, so the prototype right now is the Object.prototype
let proto = &self
.realm
.environment
.get_global_object()
.expect("Could not get the global object")
.get_field_slice("Object")
.get_field_slice("Prototype");

let func = FunctionObject::create_ordinary(
proto.clone(),
args.clone(), // TODO: args shouldn't need to be a reference it should be passed by value
FunctionBody::Ordinary(*expr.clone()),
ThisMode::Lexical,
&mut self.realm,
FunctionKind::Normal,
);

let val = Gc::new(ValueData::FunctionObj(Box::new(func)));

// Create a new function environment
let func_env = new_function_environment(
val.clone(),
Gc::new(ValueData::Undefined),
Some(self.realm.environment.get_current_environment().clone()),
);

// Set the environment in an internal slot
val.borrow().set_internal_slot("environment", func_env);

// Set the name and assign it in the current environment
if name.is_some() {
self.realm.environment.create_mutable_binding(
name.clone().expect("No name was supplied"),
false,
VariableScope::Function,
);

self.realm.environment.initialize_binding(
name.as_ref().expect("Could not get name as reference"),
val.clone(),
)
}

Ok(val)
}
Node::ArrowFunctionDecl(ref args, ref expr) => {
Expand Down

0 comments on commit f959e1e

Please sign in to comment.