From f959e1e0cd5b471c64b8dd09d0d279b281128aa2 Mon Sep 17 00:00:00 2001 From: Jason Williams Date: Mon, 20 Apr 2020 09:44:01 +0100 Subject: [PATCH] get/set environment --- boa/src/builtins/function_object.rs | 46 +++++++++++++++++++++++++---- boa/src/exec/mod.rs | 37 +++++++++++++++++++++-- 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/boa/src/builtins/function_object.rs b/boa/src/builtins/function_object.rs index 895c12e4bb5..018ea041425 100644 --- a/boa/src/builtins/function_object.rs +++ b/boa/src/builtins/function_object.rs @@ -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) @@ -68,8 +67,8 @@ pub struct Function { pub params: Vec, /// This Mode pub this_mode: ThisMode, - /// Reference to the current Environment Record - pub environment: Environment, + // Environment + pub environment: Option, } impl Function { @@ -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, }; @@ -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 + /// + /// + pub fn call( + &self, + this: &Value, + args_list: &Vec, + 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 { diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 678a3e14e35..9b04f3f4249 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -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, @@ -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) => {