diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index b9b8ae9dc49..98f3728b233 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -126,13 +126,13 @@ impl Function { local_env .borrow_mut() // Function parameters can share names in JavaScript... - .create_mutable_binding(param.name().to_owned(), false, true) + .create_mutable_binding(param.name().to_owned(), false, true, context) .expect("Failed to create binding for rest param"); // Set Binding to value local_env .borrow_mut() - .initialize_binding(param.name(), array) + .initialize_binding(param.name(), array, context) .expect("Failed to initialize rest param"); } @@ -142,17 +142,18 @@ impl Function { param: &FormalParameter, value: Value, local_env: &Environment, + context: &mut Context, ) { // Create binding local_env .borrow_mut() - .create_mutable_binding(param.name().to_owned(), false, true) + .create_mutable_binding(param.name().to_owned(), false, true, context) .expect("Failed to create binding"); // Set Binding to value local_env .borrow_mut() - .initialize_binding(param.name(), value) + .initialize_binding(param.name(), value, context) .expect("Failed to intialize binding"); } diff --git a/boa/src/context.rs b/boa/src/context.rs index 5b564ebca8d..fdde1d69da6 100644 --- a/boa/src/context.rs +++ b/boa/src/context.rs @@ -621,8 +621,7 @@ impl Context { pub(crate) fn set_value(&mut self, node: &Node, value: Value) -> Result { match node { Node::Identifier(ref name) => { - self.set_mutable_binding(name.as_ref(), value.clone(), true) - .map_err(|e| e.to_error(self))?; + self.set_mutable_binding(name.as_ref(), value.clone(), true)?; Ok(value) } Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node diff --git a/boa/src/environment/declarative_environment_record.rs b/boa/src/environment/declarative_environment_record.rs index 7d585b739a4..2dca069817d 100644 --- a/boa/src/environment/declarative_environment_record.rs +++ b/boa/src/environment/declarative_environment_record.rs @@ -5,14 +5,13 @@ //! A declarative Environment Record binds the set of identifiers defined by the declarations contained within its scope. //! More info: [ECMA-262 sec-declarative-environment-records](https://tc39.es/ecma262/#sec-declarative-environment-records) -use super::ErrorKind; use crate::{ environment::{ environment_record_trait::EnvironmentRecordTrait, lexical_environment::{Environment, EnvironmentType}, }, gc::{Finalize, Trace}, - Value, + Context, Result, Value, }; use rustc_hash::FxHashMap; @@ -47,7 +46,8 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { name: String, deletion: bool, allow_name_reuse: bool, - ) -> Result<(), ErrorKind> { + _: &mut Context, + ) -> Result<()> { if !allow_name_reuse { assert!( !self.env_rec.contains_key(&name), @@ -68,7 +68,12 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { Ok(()) } - fn create_immutable_binding(&mut self, name: String, strict: bool) -> Result<(), ErrorKind> { + fn create_immutable_binding( + &mut self, + name: String, + strict: bool, + _: &mut Context, + ) -> Result<()> { assert!( !self.env_rec.contains_key(&name), "Identifier {} has already been declared", @@ -87,7 +92,7 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { Ok(()) } - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + fn initialize_binding(&mut self, name: &str, value: Value, _: &mut Context) -> Result<()> { if let Some(ref mut record) = self.env_rec.get_mut(name) { if record.value.is_none() { record.value = Some(value); @@ -103,17 +108,15 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { name: &str, value: Value, mut strict: bool, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { if self.env_rec.get(name).is_none() { if strict { - return Err(ErrorKind::new_reference_error(format!( - "{} not found", - name - ))); + return Err(context.construct_reference_error(format!("{} not found", name))); } - self.create_mutable_binding(name.to_owned(), true, false)?; - self.initialize_binding(name, value)?; + self.create_mutable_binding(name.to_owned(), true, false, context)?; + self.initialize_binding(name, value, context)?; return Ok(()); } @@ -122,32 +125,26 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { strict = true } if record.value.is_none() { - return Err(ErrorKind::new_reference_error(format!( - "{} has not been initialized", - name - ))); + return Err( + context.construct_reference_error(format!("{} has not been initialized", name)) + ); } if record.mutable { record.value = Some(value); } else if strict { - return Err(ErrorKind::new_type_error(format!( - "Cannot mutate an immutable binding {}", - name - ))); + return Err(context + .construct_type_error(format!("Cannot mutate an immutable binding {}", name))); } Ok(()) } - fn get_binding_value(&self, name: &str, _strict: bool) -> Result { + fn get_binding_value(&self, name: &str, _strict: bool, context: &mut Context) -> Result { if let Some(binding) = self.env_rec.get(name) { if let Some(ref val) = binding.value { Ok(val.clone()) } else { - Err(ErrorKind::new_reference_error(format!( - "{} is an uninitialized binding", - name - ))) + context.throw_reference_error(format!("{} is an uninitialized binding", name)) } } else { panic!("Cannot get binding value for {}", name); @@ -172,7 +169,7 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord { false } - fn get_this_binding(&self) -> Result { + fn get_this_binding(&self, _: &mut Context) -> Result { Ok(Value::undefined()) } diff --git a/boa/src/environment/environment_record_trait.rs b/boa/src/environment/environment_record_trait.rs index 1cf0243121b..5d2a76a1137 100644 --- a/boa/src/environment/environment_record_trait.rs +++ b/boa/src/environment/environment_record_trait.rs @@ -8,11 +8,10 @@ //! //! There are 5 Environment record kinds. They all have methods in common, these are implemented as a the `EnvironmentRecordTrait` //! -use super::ErrorKind; use crate::{ environment::lexical_environment::{Environment, EnvironmentType}, gc::{Finalize, Trace}, - Value, + Context, Result, Value, }; use std::fmt::Debug; @@ -36,18 +35,25 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { name: String, deletion: bool, allow_name_reuse: bool, - ) -> Result<(), ErrorKind>; + context: &mut Context, + ) -> Result<()>; /// Create a new but uninitialized immutable binding in an Environment Record. /// The String value N is the text of the bound name. /// If strict is true then attempts to set it after it has been initialized will always throw an exception, /// regardless of the strict mode setting of operations that reference that binding. - fn create_immutable_binding(&mut self, name: String, strict: bool) -> Result<(), ErrorKind>; + fn create_immutable_binding( + &mut self, + name: String, + strict: bool, + context: &mut Context, + ) -> Result<()>; /// Set the value of an already existing but uninitialized binding in an Environment Record. /// The String value N is the text of the bound name. /// V is the value for the binding and is a value of any ECMAScript language type. - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind>; + fn initialize_binding(&mut self, name: &str, value: Value, context: &mut Context) + -> Result<()>; /// Set the value of an already existing mutable binding in an Environment Record. /// The String value `name` is the text of the bound name. @@ -58,13 +64,14 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind>; + context: &mut Context, + ) -> Result<()>; /// Returns the value of an already existing binding from an Environment Record. /// The String value N is the text of the bound name. /// S is used to identify references originating in strict mode code or that /// otherwise require strict mode reference semantics. - fn get_binding_value(&self, name: &str, strict: bool) -> Result; + fn get_binding_value(&self, name: &str, strict: bool, context: &mut Context) -> Result; /// Delete a binding from an Environment Record. /// The String value name is the text of the bound name. @@ -77,7 +84,7 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize { fn has_this_binding(&self) -> bool; /// Return the `this` binding from the environment - fn get_this_binding(&self) -> Result; + fn get_this_binding(&self, context: &mut Context) -> Result; /// Determine if an Environment Record establishes a super method binding. /// Return true if it does and false if it does not. diff --git a/boa/src/environment/function_environment_record.rs b/boa/src/environment/function_environment_record.rs index 441c15c1844..f2fc4540bb2 100644 --- a/boa/src/environment/function_environment_record.rs +++ b/boa/src/environment/function_environment_record.rs @@ -8,7 +8,6 @@ //! from within the function. //! More info: -use super::ErrorKind; use crate::{ environment::{ declarative_environment_record::DeclarativeEnvironmentRecordBinding, @@ -17,7 +16,7 @@ use crate::{ }, gc::{empty_trace, Finalize, Trace}, object::GcObject, - Value, + Context, Result, Value, }; use rustc_hash::FxHashMap; @@ -61,16 +60,16 @@ pub struct FunctionEnvironmentRecord { } impl FunctionEnvironmentRecord { - pub fn bind_this_value(&mut self, value: Value) -> Result { + pub fn bind_this_value(&mut self, value: Value, context: &mut Context) -> Result { match self.this_binding_status { // You can not bind an arrow function, their `this` value comes from the lexical scope above BindingStatus::Lexical => { panic!("Cannot bind to an arrow function!"); } // You can not bind a function twice - BindingStatus::Initialized => Err(ErrorKind::new_reference_error( - "Cannot bind to an initialised function!", - )), + BindingStatus::Initialized => { + context.throw_reference_error("Cannot bind to an initialised function!") + } BindingStatus::Uninitialized => { self.this_value = value.clone(); @@ -103,7 +102,8 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { name: String, deletion: bool, allow_name_reuse: bool, - ) -> Result<(), ErrorKind> { + _: &mut Context, + ) -> Result<()> { if !allow_name_reuse { assert!( !self.env_rec.contains_key(&name), @@ -124,20 +124,25 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { Ok(()) } - fn get_this_binding(&self) -> Result { + fn get_this_binding(&self, context: &mut Context) -> Result { match self.this_binding_status { BindingStatus::Lexical => { panic!("There is no this for a lexical function record"); } - BindingStatus::Uninitialized => Err(ErrorKind::new_reference_error( - "Uninitialised binding for this function", - )), + BindingStatus::Uninitialized => { + context.throw_reference_error("Uninitialised binding for this function") + } BindingStatus::Initialized => Ok(self.this_value.clone()), } } - fn create_immutable_binding(&mut self, name: String, strict: bool) -> Result<(), ErrorKind> { + fn create_immutable_binding( + &mut self, + name: String, + strict: bool, + _: &mut Context, + ) -> Result<()> { assert!( !self.env_rec.contains_key(&name), "Identifier {} has already been declared", @@ -156,7 +161,7 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { Ok(()) } - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + fn initialize_binding(&mut self, name: &str, value: Value, _: &mut Context) -> Result<()> { if let Some(ref mut record) = self.env_rec.get_mut(name) { if record.value.is_none() { record.value = Some(value); @@ -172,17 +177,15 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { name: &str, value: Value, mut strict: bool, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { if self.env_rec.get(name).is_none() { if strict { - return Err(ErrorKind::new_reference_error(format!( - "{} not found", - name - ))); + return Err(context.construct_reference_error(format!("{} not found", name))); } - self.create_mutable_binding(name.to_owned(), true, false)?; - self.initialize_binding(name, value)?; + self.create_mutable_binding(name.to_owned(), true, false, context)?; + self.initialize_binding(name, value, context)?; return Ok(()); } @@ -191,32 +194,26 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord { strict = true } if record.value.is_none() { - return Err(ErrorKind::new_reference_error(format!( - "{} has not been initialized", - name - ))); + return Err( + context.construct_reference_error(format!("{} has not been initialized", name)) + ); } if record.mutable { record.value = Some(value); } else if strict { - return Err(ErrorKind::new_type_error(format!( - "Cannot mutate an immutable binding {}", - name - ))); + return Err(context + .construct_type_error(format!("Cannot mutate an immutable binding {}", name))); } Ok(()) } - fn get_binding_value(&self, name: &str, _strict: bool) -> Result { + fn get_binding_value(&self, name: &str, _strict: bool, context: &mut Context) -> Result { if let Some(binding) = self.env_rec.get(name) { if let Some(ref val) = binding.value { Ok(val.clone()) } else { - Err(ErrorKind::new_reference_error(format!( - "{} is an uninitialized binding", - name - ))) + context.throw_reference_error(format!("{} is an uninitialized binding", name)) } } else { panic!("Cannot get binding value for {}", name); diff --git a/boa/src/environment/global_environment_record.rs b/boa/src/environment/global_environment_record.rs index e9da576e8b3..17015dc45a4 100644 --- a/boa/src/environment/global_environment_record.rs +++ b/boa/src/environment/global_environment_record.rs @@ -7,7 +7,6 @@ //! that occur within a Script. //! More info: -use super::ErrorKind; use crate::{ environment::{ declarative_environment_record::DeclarativeEnvironmentRecord, @@ -17,7 +16,7 @@ use crate::{ }, gc::{Finalize, Trace}, property::{Attribute, DataDescriptor}, - Value, + Context, Result, Value, }; use rustc_hash::FxHashSet; @@ -80,14 +79,15 @@ impl GlobalEnvironmentRecord { &mut self, name: String, deletion: bool, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { let obj_rec = &mut self.object_record; let global_object = &obj_rec.bindings; let has_property = global_object.has_field(name.as_str()); let extensible = global_object.is_extensible(); if !has_property && extensible { - obj_rec.create_mutable_binding(name.clone(), deletion, false)?; - obj_rec.initialize_binding(&name, Value::undefined())?; + obj_rec.create_mutable_binding(name.clone(), deletion, false, context)?; + obj_rec.initialize_binding(&name, Value::undefined(), context)?; } let var_declared_names = &mut self.var_names; @@ -120,7 +120,7 @@ impl GlobalEnvironmentRecord { } impl EnvironmentRecordTrait for GlobalEnvironmentRecord { - fn get_this_binding(&self) -> Result { + fn get_this_binding(&self, _: &mut Context) -> Result { Ok(self.global_this_binding.clone()) } @@ -136,40 +136,51 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord { name: String, deletion: bool, allow_name_reuse: bool, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { if !allow_name_reuse && self.declarative_record.has_binding(&name) { - return Err(ErrorKind::new_type_error(format!( - "Binding already exists for {}", - name - ))); + return Err( + context.construct_type_error(format!("Binding already exists for {}", name)) + ); } self.declarative_record - .create_mutable_binding(name, deletion, allow_name_reuse) + .create_mutable_binding(name, deletion, allow_name_reuse, context) } - fn create_immutable_binding(&mut self, name: String, strict: bool) -> Result<(), ErrorKind> { + fn create_immutable_binding( + &mut self, + name: String, + strict: bool, + context: &mut Context, + ) -> Result<()> { if self.declarative_record.has_binding(&name) { - return Err(ErrorKind::new_type_error(format!( - "Binding already exists for {}", - name - ))); + return Err( + context.construct_type_error(format!("Binding already exists for {}", name)) + ); } self.declarative_record - .create_immutable_binding(name, strict) + .create_immutable_binding(name, strict, context) } - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + fn initialize_binding( + &mut self, + name: &str, + value: Value, + context: &mut Context, + ) -> Result<()> { if self.declarative_record.has_binding(&name) { - return self.declarative_record.initialize_binding(name, value); + return self + .declarative_record + .initialize_binding(name, value, context); } assert!( self.object_record.has_binding(name), "Binding must be in object_record" ); - self.object_record.initialize_binding(name, value) + self.object_record.initialize_binding(name, value, context) } fn set_mutable_binding( @@ -177,20 +188,24 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord { name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind> { + context: &mut Context, + ) -> Result<()> { if self.declarative_record.has_binding(&name) { return self .declarative_record - .set_mutable_binding(name, value, strict); + .set_mutable_binding(name, value, strict, context); } - self.object_record.set_mutable_binding(name, value, strict) + self.object_record + .set_mutable_binding(name, value, strict, context) } - fn get_binding_value(&self, name: &str, strict: bool) -> Result { + fn get_binding_value(&self, name: &str, strict: bool, context: &mut Context) -> Result { if self.declarative_record.has_binding(&name) { - return self.declarative_record.get_binding_value(name, strict); + return self + .declarative_record + .get_binding_value(name, strict, context); } - self.object_record.get_binding_value(name, strict) + self.object_record.get_binding_value(name, strict, context) } fn delete_binding(&mut self, name: &str) -> bool { diff --git a/boa/src/environment/lexical_environment.rs b/boa/src/environment/lexical_environment.rs index 6125d409677..205dbb5c753 100644 --- a/boa/src/environment/lexical_environment.rs +++ b/boa/src/environment/lexical_environment.rs @@ -5,7 +5,6 @@ //! The following operations are used to operate upon lexical environments //! This is the entrypoint to lexical environments. -use super::ErrorKind; use crate::{ environment::{ declarative_environment_record::DeclarativeEnvironmentRecord, @@ -15,7 +14,7 @@ use crate::{ object_environment_record::ObjectEnvironmentRecord, }, object::GcObject, - BoaProfiler, Context, Value, + BoaProfiler, Context, Result, Value, }; use gc::{Gc, GcCell}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -86,21 +85,21 @@ impl LexicalEnvironment { // TODO: move implementation to a better place. impl Context { - pub fn push_environment(&mut self, env: Environment) { + pub(crate) fn push_environment(&mut self, env: Environment) { let current_env: Environment = self.get_current_environment().clone(); env.borrow_mut().set_outer_environment(current_env); self.realm.environment.environment_stack.push_back(env); } - pub fn pop_environment(&mut self) -> Option { + pub(crate) fn pop_environment(&mut self) -> Option { self.realm.environment.environment_stack.pop_back() } - pub fn environments(&self) -> impl Iterator { + pub(crate) fn environments(&self) -> impl Iterator { self.realm.environment.environment_stack.iter().rev() } - pub fn get_global_object(&self) -> Option { + pub(crate) fn get_global_object(&self) -> Option { self.realm .environment .environment_stack @@ -110,24 +109,28 @@ impl Context { .get_global_object() } - pub fn get_this_binding(&self) -> Result { - self.environments() + pub(crate) fn get_this_binding(&mut self) -> Result { + let env = self + .environments() .find(|env| env.borrow().has_this_binding()) - .map(|env| env.borrow().get_this_binding()) + .cloned(); + + env.map(|env| env.borrow().get_this_binding(self)) .unwrap_or_else(|| Ok(Value::Undefined)) } - pub fn create_mutable_binding( + pub(crate) fn create_mutable_binding( &mut self, name: String, deletion: bool, scope: VariableScope, - ) -> Result<(), ErrorKind> { + ) -> Result<()> { match scope { VariableScope::Block => self - .get_current_environment() + .get_current_environment_ref() + .clone() .borrow_mut() - .create_mutable_binding(name, deletion, false), + .create_mutable_binding(name, deletion, false, self), VariableScope::Function => { // Find the first function or global environment (from the top of the stack) let env = self @@ -138,25 +141,28 @@ impl Context { EnvironmentType::Function | EnvironmentType::Global ) }) - .expect("No function or global environment"); + .expect("No function or global environment") + .clone(); - env.borrow_mut() - .create_mutable_binding(name, deletion, false) + env.clone() + .borrow_mut() + .create_mutable_binding(name, deletion, false, self) } } } - pub fn create_immutable_binding( + pub(crate) fn create_immutable_binding( &mut self, name: String, deletion: bool, scope: VariableScope, - ) -> Result<(), ErrorKind> { + ) -> Result<()> { match scope { VariableScope::Block => self .get_current_environment() + .clone() .borrow_mut() - .create_immutable_binding(name, deletion), + .create_immutable_binding(name, deletion, self), VariableScope::Function => { // Find the first function or global environment (from the top of the stack) let env = self @@ -169,24 +175,26 @@ impl Context { }) .expect("No function or global environment"); - env.borrow_mut().create_immutable_binding(name, deletion) + env.clone() + .borrow_mut() + .create_immutable_binding(name, deletion, self) } } } - pub fn set_mutable_binding( + pub(crate) fn set_mutable_binding( &mut self, name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind> { + ) -> Result<()> { // Find the first environment which has the given binding let env = self .environments() .find(|env| env.borrow().has_binding(name)); let env = if let Some(env) = env { - env + env.clone() } else { // global_env doesn't need has_binding to be satisfied in non strict mode self.realm @@ -194,11 +202,14 @@ impl Context { .environment_stack .get(0) .expect("Environment stack underflow") + .clone() }; - env.borrow_mut().set_mutable_binding(name, value, strict) + env.clone() + .borrow_mut() + .set_mutable_binding(name, value, strict, self) } - pub fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + pub(crate) fn initialize_binding(&mut self, name: &str, value: Value) -> Result<()> { // Find the first environment which has the given binding let env = self .environments() @@ -214,12 +225,14 @@ impl Context { .get(0) .expect("Environment stack underflow") }; - env.borrow_mut().initialize_binding(name, value) + env.clone() + .borrow_mut() + .initialize_binding(name, value, self) } /// get_current_environment_ref is used when you only need to borrow the environment /// (you only need to add a new variable binding, or you want to fetch a value) - pub fn get_current_environment_ref(&self) -> &Environment { + pub(crate) fn get_current_environment_ref(&self) -> &Environment { self.realm .environment .environment_stack @@ -229,7 +242,7 @@ impl Context { /// When neededing to clone an environment (linking it with another environnment) /// cloning is more suited. The GC will remove the env once nothing is linking to it anymore - pub fn get_current_environment(&mut self) -> &mut Environment { + pub(crate) fn get_current_environment(&mut self) -> &mut Environment { self.realm .environment .environment_stack @@ -237,20 +250,20 @@ impl Context { .expect("Could not get mutable reference to back object") } - pub fn has_binding(&self, name: &str) -> bool { + pub(crate) fn has_binding(&self, name: &str) -> bool { self.environments() .any(|env| env.borrow().has_binding(name)) } - pub fn get_binding_value(&self, name: &str) -> Result { - self.environments() + pub(crate) fn get_binding_value(&mut self, name: &str) -> Result { + let env = self + .environments() .find(|env| env.borrow().has_binding(name)) - .map(|env| env.borrow().get_binding_value(name, false)) + .cloned(); + + env.map(|env| env.borrow().get_binding_value(name, false, self)) .unwrap_or_else(|| { - Err(ErrorKind::new_reference_error(format!( - "{} is not defined", - name - ))) + Err(self.construct_reference_error(format!("{} is not defined", name))) }) } } @@ -271,6 +284,7 @@ pub fn new_function_environment( outer: Option, binding_status: BindingStatus, new_target: Value, + context: &mut Context, ) -> Environment { let mut func_env = FunctionEnvironmentRecord { env_rec: FxHashMap::default(), @@ -283,7 +297,7 @@ pub fn new_function_environment( }; // If a `this` value has been passed, bind it to the environment if let Some(v) = this { - func_env.bind_this_value(v).unwrap(); + func_env.bind_this_value(v, context).unwrap(); } Gc::new(GcCell::new(Box::new(func_env))) } diff --git a/boa/src/environment/mod.rs b/boa/src/environment/mod.rs index ceb1773c38a..3e4d89bbebb 100644 --- a/boa/src/environment/mod.rs +++ b/boa/src/environment/mod.rs @@ -6,35 +6,3 @@ pub mod function_environment_record; pub mod global_environment_record; pub mod lexical_environment; pub mod object_environment_record; - -#[derive(Debug)] -pub enum ErrorKind { - ReferenceError(Box), - TypeError(Box), -} - -use crate::value::Value; -use crate::Context; - -impl ErrorKind { - pub fn to_error(&self, ctx: &mut Context) -> Value { - match self { - ErrorKind::ReferenceError(msg) => ctx.construct_reference_error(msg.clone()), - ErrorKind::TypeError(msg) => ctx.construct_type_error(msg.clone()), - } - } - - pub fn new_reference_error(msg: M) -> Self - where - M: Into>, - { - Self::ReferenceError(msg.into()) - } - - pub fn new_type_error(msg: M) -> Self - where - M: Into>, - { - Self::TypeError(msg.into()) - } -} diff --git a/boa/src/environment/object_environment_record.rs b/boa/src/environment/object_environment_record.rs index 1c5639fc737..4ba0f817580 100644 --- a/boa/src/environment/object_environment_record.rs +++ b/boa/src/environment/object_environment_record.rs @@ -6,16 +6,15 @@ //! Property keys that are not strings in the form of an `IdentifierName` are not included in the set of bound identifiers. //! More info: [Object Records](https://tc39.es/ecma262/#sec-object-environment-records) -use super::*; -use crate::property::PropertyDescriptor; use crate::{ environment::{ environment_record_trait::EnvironmentRecordTrait, lexical_environment::{Environment, EnvironmentType}, }, gc::{Finalize, Trace}, + property::PropertyDescriptor, property::{Attribute, DataDescriptor}, - Value, + Context, Result, Value, }; #[derive(Debug, Trace, Finalize, Clone)] @@ -42,7 +41,8 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { name: String, deletion: bool, _allow_name_reuse: bool, - ) -> Result<(), ErrorKind> { + _: &mut Context, + ) -> Result<()> { // TODO: could save time here and not bother generating a new undefined object, // only for it to be replace with the real value later. We could just add the name to a Vector instead let bindings = &mut self.bindings; @@ -56,16 +56,26 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { Ok(()) } - fn create_immutable_binding(&mut self, _name: String, _strict: bool) -> Result<(), ErrorKind> { + fn create_immutable_binding( + &mut self, + _name: String, + _strict: bool, + _: &mut Context, + ) -> Result<()> { Ok(()) } - fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> { + fn initialize_binding( + &mut self, + name: &str, + value: Value, + context: &mut Context, + ) -> Result<()> { // We should never need to check if a binding has been created, // As all calls to create_mutable_binding are followed by initialized binding // The below is just a check. debug_assert!(self.has_binding(&name)); - self.set_mutable_binding(name, value, false) + self.set_mutable_binding(name, value, false, context) } fn set_mutable_binding( @@ -73,7 +83,8 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { name: &str, value: Value, strict: bool, - ) -> Result<(), ErrorKind> { + _: &mut Context, + ) -> Result<()> { debug_assert!(value.is_object() || value.is_function()); let mut property = DataDescriptor::new(value, Attribute::ENUMERABLE); property.set_configurable(strict); @@ -84,17 +95,14 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { Ok(()) } - fn get_binding_value(&self, name: &str, strict: bool) -> Result { + fn get_binding_value(&self, name: &str, strict: bool, context: &mut Context) -> Result { if self.bindings.has_field(name) { match self.bindings.get_property(name) { Some(PropertyDescriptor::Data(ref d)) => Ok(d.value()), _ => Ok(Value::undefined()), } } else if strict { - Err(ErrorKind::new_reference_error(format!( - "{} has no binding", - name - ))) + context.throw_reference_error(format!("{} has no binding", name)) } else { Ok(Value::undefined()) } @@ -109,7 +117,7 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord { false } - fn get_this_binding(&self) -> Result { + fn get_this_binding(&self, _: &mut Context) -> Result { Ok(Value::undefined()) } diff --git a/boa/src/object/gcobject.rs b/boa/src/object/gcobject.rs index cb5aea8294b..74aaa93afc2 100644 --- a/boa/src/object/gcobject.rs +++ b/boa/src/object/gcobject.rs @@ -150,6 +150,7 @@ impl GcObject { BindingStatus::Uninitialized }, Value::undefined(), + context, ); // Add argument bindings to the function environment @@ -161,19 +162,23 @@ impl GcObject { } let value = args.get(i).cloned().unwrap_or_else(Value::undefined); - function.add_arguments_to_environment(param, value, &local_env); + function + .add_arguments_to_environment(param, value, &local_env, context); } // Add arguments object let arguments_obj = create_unmapped_arguments_object(args); - local_env - .borrow_mut() - .create_mutable_binding("arguments".to_string(), false, true) - .map_err(|e| e.to_error(context))?; - local_env - .borrow_mut() - .initialize_binding("arguments", arguments_obj) - .map_err(|e| e.to_error(context))?; + local_env.borrow_mut().create_mutable_binding( + "arguments".to_string(), + false, + true, + context, + )?; + local_env.borrow_mut().initialize_binding( + "arguments", + arguments_obj, + context, + )?; context.push_environment(local_env); @@ -258,6 +263,7 @@ impl GcObject { BindingStatus::Uninitialized }, new_target.clone(), + context, ); // Add argument bindings to the function environment @@ -269,19 +275,23 @@ impl GcObject { } let value = args.get(i).cloned().unwrap_or_else(Value::undefined); - function.add_arguments_to_environment(param, value, &local_env); + function + .add_arguments_to_environment(param, value, &local_env, context); } // Add arguments object let arguments_obj = create_unmapped_arguments_object(args); - local_env - .borrow_mut() - .create_mutable_binding("arguments".to_string(), false, true) - .map_err(|e| e.to_error(context))?; - local_env - .borrow_mut() - .initialize_binding("arguments", arguments_obj) - .map_err(|e| e.to_error(context))?; + local_env.borrow_mut().create_mutable_binding( + "arguments".to_string(), + false, + true, + context, + )?; + local_env.borrow_mut().initialize_binding( + "arguments", + arguments_obj, + context, + )?; context.push_environment(local_env); @@ -305,8 +315,7 @@ impl GcObject { let _ = body.run(context); // local_env gets dropped here, its no longer needed - let binding = context.get_this_binding(); - binding.map_err(|e| e.to_error(context)) + context.get_this_binding() } FunctionBody::BuiltInFunction(_) => unreachable!("Cannot have a function in construct"), } diff --git a/boa/src/syntax/ast/node/declaration/const_decl_list/mod.rs b/boa/src/syntax/ast/node/declaration/const_decl_list/mod.rs index 651e188931c..ae09a9a2cbd 100644 --- a/boa/src/syntax/ast/node/declaration/const_decl_list/mod.rs +++ b/boa/src/syntax/ast/node/declaration/const_decl_list/mod.rs @@ -43,13 +43,13 @@ impl Executable for ConstDeclList { } else { return context.throw_syntax_error("missing = in const declaration"); }; - context - .create_immutable_binding(decl.name().to_owned(), false, VariableScope::Block) - .map_err(|e| e.to_error(context))?; + context.create_immutable_binding( + decl.name().to_owned(), + false, + VariableScope::Block, + )?; - context - .initialize_binding(decl.name(), val) - .map_err(|e| e.to_error(context))?; + context.initialize_binding(decl.name(), val)?; } Ok(Value::undefined()) } diff --git a/boa/src/syntax/ast/node/declaration/function_decl/mod.rs b/boa/src/syntax/ast/node/declaration/function_decl/mod.rs index 671570573dd..e3b68bc7670 100644 --- a/boa/src/syntax/ast/node/declaration/function_decl/mod.rs +++ b/boa/src/syntax/ast/node/declaration/function_decl/mod.rs @@ -96,17 +96,15 @@ impl Executable for FunctionDecl { val.set_field("name", self.name(), context)?; if context.has_binding(self.name()) { - context - .set_mutable_binding(self.name(), val, true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(self.name(), val, true)?; } else { - context - .create_mutable_binding(self.name().to_owned(), false, VariableScope::Function) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + self.name().to_owned(), + false, + VariableScope::Function, + )?; - context - .initialize_binding(self.name(), val) - .map_err(|e| e.to_error(context))?; + context.initialize_binding(self.name(), val)?; } Ok(Value::undefined()) } diff --git a/boa/src/syntax/ast/node/declaration/let_decl_list/mod.rs b/boa/src/syntax/ast/node/declaration/let_decl_list/mod.rs index 295d00bfc36..5f948147fdc 100644 --- a/boa/src/syntax/ast/node/declaration/let_decl_list/mod.rs +++ b/boa/src/syntax/ast/node/declaration/let_decl_list/mod.rs @@ -41,12 +41,8 @@ impl Executable for LetDeclList { Some(v) => v.run(context)?, None => Value::undefined(), }; - context - .create_mutable_binding(var.name().to_owned(), false, VariableScope::Block) - .map_err(|e| e.to_error(context))?; - context - .initialize_binding(var.name(), val) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding(var.name().to_owned(), false, VariableScope::Block)?; + context.initialize_binding(var.name(), val)?; } Ok(Value::undefined()) } diff --git a/boa/src/syntax/ast/node/declaration/var_decl_list/mod.rs b/boa/src/syntax/ast/node/declaration/var_decl_list/mod.rs index 51a66e6b3ba..c76b5969129 100644 --- a/boa/src/syntax/ast/node/declaration/var_decl_list/mod.rs +++ b/boa/src/syntax/ast/node/declaration/var_decl_list/mod.rs @@ -45,17 +45,15 @@ impl Executable for VarDeclList { if context.has_binding(var.name()) { if var.init().is_some() { - context - .set_mutable_binding(var.name(), val, true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(var.name(), val, true)?; } } else { - context - .create_mutable_binding(var.name().to_owned(), false, VariableScope::Function) - .map_err(|e| e.to_error(context))?; - context - .initialize_binding(var.name(), val) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Function, + )?; + context.initialize_binding(var.name(), val)?; } } Ok(Value::undefined()) diff --git a/boa/src/syntax/ast/node/identifier/mod.rs b/boa/src/syntax/ast/node/identifier/mod.rs index bd9b93cd12c..ca595d460e8 100644 --- a/boa/src/syntax/ast/node/identifier/mod.rs +++ b/boa/src/syntax/ast/node/identifier/mod.rs @@ -36,9 +36,7 @@ pub struct Identifier { impl Executable for Identifier { fn run(&self, context: &mut Context) -> Result { - context - .get_binding_value(self.as_ref()) - .map_err(|e| e.to_error(context)) + context.get_binding_value(self.as_ref()) } } diff --git a/boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs b/boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs index 1c9560cfe0c..1c2ee94a9de 100644 --- a/boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs +++ b/boa/src/syntax/ast/node/iteration/for_in_loop/mod.rs @@ -106,20 +106,14 @@ impl Executable for ForInLoop { Node::Identifier(ref name) => { if context.has_binding(name.as_ref()) { // Binding already exists - context - .set_mutable_binding(name.as_ref(), next_result.clone(), true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(name.as_ref(), next_result.clone(), true)?; } else { - context - .create_mutable_binding( - name.as_ref().to_owned(), - true, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - context - .initialize_binding(name.as_ref(), next_result.clone()) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + name.as_ref().to_owned(), + true, + VariableScope::Function, + )?; + context.initialize_binding(name.as_ref(), next_result.clone())?; } } Node::VarDeclList(ref list) => match list.as_ref() { @@ -129,20 +123,14 @@ impl Executable for ForInLoop { } if context.has_binding(var.name()) { - context - .set_mutable_binding(var.name(), next_result, true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(var.name(), next_result, true)?; } else { - context - .create_mutable_binding( - var.name().to_owned(), - false, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - context - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Function, + )?; + context.initialize_binding(var.name(), next_result)?; } } _ => { @@ -157,16 +145,12 @@ impl Executable for ForInLoop { return context.throw_syntax_error("a declaration in the head of a for-in loop can't have an initializer"); } - context - .create_mutable_binding( - var.name().to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - context - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + )?; + context.initialize_binding(var.name(), next_result)?; } _ => { return context.throw_syntax_error( @@ -180,16 +164,12 @@ impl Executable for ForInLoop { return context.throw_syntax_error("a declaration in the head of a for-in loop can't have an initializer"); } - context - .create_immutable_binding( - var.name().to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - context - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + context.create_immutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + )?; + context.initialize_binding(var.name(), next_result)?; } _ => { return context.throw_syntax_error( diff --git a/boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs b/boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs index a59087affa7..b11e590ce81 100644 --- a/boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs +++ b/boa/src/syntax/ast/node/iteration/for_of_loop/mod.rs @@ -96,20 +96,14 @@ impl Executable for ForOfLoop { Node::Identifier(ref name) => { if context.has_binding(name.as_ref()) { // Binding already exists - context - .set_mutable_binding(name.as_ref(), next_result.clone(), true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(name.as_ref(), next_result.clone(), true)?; } else { - context - .create_mutable_binding( - name.as_ref().to_owned(), - true, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - context - .initialize_binding(name.as_ref(), next_result.clone()) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + name.as_ref().to_owned(), + true, + VariableScope::Function, + )?; + context.initialize_binding(name.as_ref(), next_result.clone())?; } } Node::VarDeclList(ref list) => match list.as_ref() { @@ -119,20 +113,14 @@ impl Executable for ForOfLoop { } if context.has_binding(var.name()) { - context - .set_mutable_binding(var.name(), next_result, true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(var.name(), next_result, true)?; } else { - context - .create_mutable_binding( - var.name().to_owned(), - false, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - context - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Function, + )?; + context.initialize_binding(var.name(), next_result)?; } } _ => { @@ -147,17 +135,13 @@ impl Executable for ForOfLoop { return context.throw_syntax_error("a declaration in the head of a for-of loop can't have an initializer"); } - context - .create_mutable_binding( - var.name().to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + )?; - context - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + context.initialize_binding(var.name(), next_result)?; } _ => { return context.throw_syntax_error( @@ -171,16 +155,12 @@ impl Executable for ForOfLoop { return context.throw_syntax_error("a declaration in the head of a for-of loop can't have an initializer"); } - context - .create_immutable_binding( - var.name().to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - context - .initialize_binding(var.name(), next_result) - .map_err(|e| e.to_error(context))?; + context.create_immutable_binding( + var.name().to_owned(), + false, + VariableScope::Block, + )?; + context.initialize_binding(var.name(), next_result)?; } _ => { return context.throw_syntax_error( diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 3ee69d30269..f098c83afed 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -329,7 +329,7 @@ impl Executable for Node { Node::Spread(ref spread) => spread.run(context), Node::This => { // Will either return `this` binding or undefined - context.get_this_binding().map_err(|e| e.to_error(context)) + context.get_this_binding() } Node::Try(ref try_node) => try_node.run(context), Node::Break(ref break_node) => break_node.run(context), diff --git a/boa/src/syntax/ast/node/operator/assign/mod.rs b/boa/src/syntax/ast/node/operator/assign/mod.rs index 973ca6623ec..0d362ec8d12 100644 --- a/boa/src/syntax/ast/node/operator/assign/mod.rs +++ b/boa/src/syntax/ast/node/operator/assign/mod.rs @@ -60,20 +60,14 @@ impl Executable for Assign { Node::Identifier(ref name) => { if context.has_binding(name.as_ref()) { // Binding already exists - context - .set_mutable_binding(name.as_ref(), val.clone(), true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(name.as_ref(), val.clone(), true)?; } else { - context - .create_mutable_binding( - name.as_ref().to_owned(), - true, - VariableScope::Function, - ) - .map_err(|e| e.to_error(context))?; - context - .initialize_binding(name.as_ref(), val.clone()) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + name.as_ref().to_owned(), + true, + VariableScope::Function, + )?; + context.initialize_binding(name.as_ref(), val.clone())?; } } Node::GetConstField(ref get_const_field) => { diff --git a/boa/src/syntax/ast/node/operator/bin_op/mod.rs b/boa/src/syntax/ast/node/operator/bin_op/mod.rs index 12e4a1d65ba..e20291353ce 100644 --- a/boa/src/syntax/ast/node/operator/bin_op/mod.rs +++ b/boa/src/syntax/ast/node/operator/bin_op/mod.rs @@ -205,14 +205,10 @@ impl Executable for BinOp { }), op::BinOp::Assign(op) => match self.lhs() { Node::Identifier(ref name) => { - let v_a = context - .get_binding_value(name.as_ref()) - .map_err(|e| e.to_error(context))?; + let v_a = context.get_binding_value(name.as_ref())?; let value = Self::run_assign(op, v_a, self.rhs(), context)?; - context - .set_mutable_binding(name.as_ref(), value.clone(), true) - .map_err(|e| e.to_error(context))?; + context.set_mutable_binding(name.as_ref(), value.clone(), true)?; Ok(value) } Node::GetConstField(ref get_const_field) => { diff --git a/boa/src/syntax/ast/node/try_node/mod.rs b/boa/src/syntax/ast/node/try_node/mod.rs index b94e598b788..fc236b560c6 100644 --- a/boa/src/syntax/ast/node/try_node/mod.rs +++ b/boa/src/syntax/ast/node/try_node/mod.rs @@ -102,16 +102,12 @@ impl Executable for Try { context.push_environment(new_declarative_environment(Some(env))); if let Some(param) = catch.parameter() { - context - .create_mutable_binding( - param.to_owned(), - false, - VariableScope::Block, - ) - .map_err(|e| e.to_error(context))?; - context - .initialize_binding(param, err) - .map_err(|e| e.to_error(context))?; + context.create_mutable_binding( + param.to_owned(), + false, + VariableScope::Block, + )?; + context.initialize_binding(param, err)?; } } diff --git a/boa_unicode/src/tests.rs b/boa_unicode/src/tests.rs index 316b3106097..b433c4c6d20 100644 --- a/boa_unicode/src/tests.rs +++ b/boa_unicode/src/tests.rs @@ -1,4 +1,3 @@ -use unicode_general_category; #[test] fn check_unicode_version() { assert_eq!( diff --git a/test262 b/test262 index 00014894735..6cf3433cf8f 160000 --- a/test262 +++ b/test262 @@ -1 +1 @@ -Subproject commit 00014894735c3bee62bed234594abf387ea0c57b +Subproject commit 6cf3433cf8f44c471a7e4f47e5ba36d32ebb7b69