Skip to content

Commit

Permalink
Add Context to environment methods
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat committed Feb 17, 2021
1 parent 1c2b61f commit 9c88f59
Show file tree
Hide file tree
Showing 23 changed files with 310 additions and 360 deletions.
9 changes: 5 additions & 4 deletions boa/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

Expand All @@ -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");
}

Expand Down
3 changes: 1 addition & 2 deletions boa/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,8 +621,7 @@ impl Context {
pub(crate) fn set_value(&mut self, node: &Node, value: Value) -> Result<Value> {
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
Expand Down
49 changes: 23 additions & 26 deletions boa/src/environment/declarative_environment_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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),
Expand All @@ -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",
Expand All @@ -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);
Expand All @@ -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(());
}

Expand All @@ -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<Value, ErrorKind> {
fn get_binding_value(&self, name: &str, _strict: bool, context: &mut Context) -> Result<Value> {
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);
Expand All @@ -172,7 +169,7 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord {
false
}

fn get_this_binding(&self) -> Result<Value, ErrorKind> {
fn get_this_binding(&self, _: &mut Context) -> Result<Value> {
Ok(Value::undefined())
}

Expand Down
23 changes: 15 additions & 8 deletions boa/src/environment/environment_record_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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.
Expand All @@ -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<Value, ErrorKind>;
fn get_binding_value(&self, name: &str, strict: bool, context: &mut Context) -> Result<Value>;

/// Delete a binding from an Environment Record.
/// The String value name is the text of the bound name.
Expand All @@ -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<Value, ErrorKind>;
fn get_this_binding(&self, context: &mut Context) -> Result<Value>;

/// Determine if an Environment Record establishes a super method binding.
/// Return true if it does and false if it does not.
Expand Down
63 changes: 30 additions & 33 deletions boa/src/environment/function_environment_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
//! from within the function.
//! More info: <https://tc39.es/ecma262/#sec-function-environment-records>

use super::ErrorKind;
use crate::{
environment::{
declarative_environment_record::DeclarativeEnvironmentRecordBinding,
Expand All @@ -17,7 +16,7 @@ use crate::{
},
gc::{empty_trace, Finalize, Trace},
object::GcObject,
Value,
Context, Result, Value,
};
use rustc_hash::FxHashMap;

Expand Down Expand Up @@ -61,16 +60,16 @@ pub struct FunctionEnvironmentRecord {
}

impl FunctionEnvironmentRecord {
pub fn bind_this_value(&mut self, value: Value) -> Result<Value, ErrorKind> {
pub fn bind_this_value(&mut self, value: Value, context: &mut Context) -> Result<Value> {
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();
Expand Down Expand Up @@ -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),
Expand All @@ -124,20 +124,25 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord {
Ok(())
}

fn get_this_binding(&self) -> Result<Value, ErrorKind> {
fn get_this_binding(&self, context: &mut Context) -> Result<Value> {
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",
Expand All @@ -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);
Expand All @@ -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(());
}

Expand All @@ -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<Value, ErrorKind> {
fn get_binding_value(&self, name: &str, _strict: bool, context: &mut Context) -> Result<Value> {
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);
Expand Down
Loading

0 comments on commit 9c88f59

Please sign in to comment.