Skip to content

Commit

Permalink
Refactor environment records
Browse files Browse the repository at this point in the history
  • Loading branch information
0x7D2B committed Mar 5, 2021
1 parent 77ab0c1 commit 33b3634
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 104 deletions.
4 changes: 2 additions & 2 deletions boa/src/environment/declarative_environment_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord {
Value::undefined()
}

fn get_outer_environment(&self) -> Option<Environment> {
self.outer_env.as_ref().cloned()
fn get_outer_environment_ref(&self) -> Option<&Environment> {
self.outer_env.as_ref()
}

fn set_outer_environment(&mut self, env: Environment) {
Expand Down
112 changes: 111 additions & 1 deletion boa/src/environment/environment_record_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//! 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::VariableScope;
use crate::{
environment::lexical_environment::{Environment, EnvironmentType},
gc::{Finalize, Trace},
Expand Down Expand Up @@ -88,7 +89,10 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize {
fn with_base_object(&self) -> Value;

/// Get the next environment up
fn get_outer_environment(&self) -> Option<Environment>;
fn get_outer_environment_ref(&self) -> Option<&Environment>;
fn get_outer_environment(&self) -> Option<Environment> {
self.get_outer_environment_ref().cloned()
}

/// Set the next environment up
fn set_outer_environment(&mut self, env: Environment);
Expand All @@ -98,4 +102,110 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize {

/// Fetch global variable
fn get_global_object(&self) -> Option<Value>;

fn recursive_get_this_binding(&self) -> Result<Value, ErrorKind> {
if self.has_this_binding() {
self.get_this_binding()
} else {
match self.get_outer_environment_ref() {
Some(outer) => outer.borrow().recursive_get_this_binding(),
None => Ok(Value::Undefined),
}
}
}

/// Create mutable binding while handling outer environments
fn recursive_create_mutable_binding(
&mut self,
name: String,
deletion: bool,
scope: VariableScope,
) -> Result<(), ErrorKind> {
match (scope, self.get_environment_type()) {
(VariableScope::Block, _)
| (VariableScope::Function, EnvironmentType::Function)
| (VariableScope::Function, EnvironmentType::Global) => {
self.create_mutable_binding(name, deletion, false)
}
_ => self
.get_outer_environment_ref()
.expect("No function or global environment")
.borrow_mut()
.recursive_create_mutable_binding(name, deletion, scope),
}
}

/// Create immutable binding while handling outer environments
fn recursive_create_immutable_binding(
&mut self,
name: String,
deletion: bool,
scope: VariableScope,
) -> Result<(), ErrorKind> {
match (scope, self.get_environment_type()) {
(VariableScope::Block, _)
| (VariableScope::Function, EnvironmentType::Function)
| (VariableScope::Function, EnvironmentType::Global) => {
self.create_immutable_binding(name, deletion)
}
_ => self
.get_outer_environment_ref()
.expect("No function or global environment")
.borrow_mut()
.recursive_create_immutable_binding(name, deletion, scope),
}
}

/// Set mutable binding while handling outer environments
fn recursive_set_mutable_binding(
&mut self,
name: &str,
value: Value,
strict: bool,
) -> Result<(), ErrorKind> {
if self.has_binding(name) || self.get_environment_type() == EnvironmentType::Global {
self.set_mutable_binding(name, value, strict)
} else {
self.get_outer_environment_ref()
.expect("Environment stack underflow")
.borrow_mut()
.recursive_set_mutable_binding(name, value, strict)
}
}

/// Initialize binding while handling outer environments
fn recursive_initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> {
if self.has_binding(name) || self.get_environment_type() == EnvironmentType::Global {
self.initialize_binding(name, value)
} else {
self.get_outer_environment_ref()
.expect("Environment stack underflow")
.borrow_mut()
.recursive_initialize_binding(name, value)
}
}

/// Check if a binding exists in current or any outer environment
fn recursive_has_binding(&self, name: &str) -> bool {
self.has_binding(name)
|| match self.get_outer_environment_ref() {
Some(outer) => outer.borrow().recursive_has_binding(name),
None => false,
}
}

/// Retrieve binding from current or any outer environment
fn recursive_get_binding_value(&self, name: &str) -> Result<Value, ErrorKind> {
if self.has_binding(name) {
self.get_binding_value(name, false)
} else {
match self.get_outer_environment_ref() {
Some(outer) => outer.borrow().recursive_get_binding_value(name),
None => Err(ErrorKind::new_reference_error(format!(
"{} is not defined",
name
))),
}
}
}
}
4 changes: 2 additions & 2 deletions boa/src/environment/function_environment_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord {
Value::undefined()
}

fn get_outer_environment(&self) -> Option<Environment> {
self.declarative_record.get_outer_environment()
fn get_outer_environment_ref(&self) -> Option<&Environment> {
self.declarative_record.get_outer_environment_ref()
}

fn set_outer_environment(&mut self, env: Environment) {
Expand Down
4 changes: 4 additions & 0 deletions boa/src/environment/global_environment_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord {
None
}

fn get_outer_environment_ref(&self) -> Option<&Environment> {
None
}

fn set_outer_environment(&mut self, _env: Environment) {
// TODO: Implement
panic!("Not implemented yet")
Expand Down
116 changes: 22 additions & 94 deletions boa/src/environment/lexical_environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,25 +100,16 @@ impl LexicalEnvironment {
self.environment_stack.pop_back()
}

fn environments(&self) -> impl Iterator<Item = Environment> {
std::iter::successors(Some(self.get_current_environment_ref().clone()), |env| {
env.borrow().get_outer_environment()
})
}

pub fn get_global_object(&self) -> Option<Value> {
self.environment_stack
.get(0)
.expect("")
self.get_current_environment_ref()
.borrow()
.get_global_object()
}

pub fn get_this_binding(&self) -> Result<Value, ErrorKind> {
self.environments()
.find(|env| env.borrow().has_this_binding())
.map(|env| env.borrow().get_this_binding())
.unwrap_or_else(|| Ok(Value::Undefined))
self.get_current_environment_ref()
.borrow()
.recursive_get_this_binding()
}

pub fn create_mutable_binding(
Expand All @@ -127,25 +118,9 @@ impl LexicalEnvironment {
deletion: bool,
scope: VariableScope,
) -> Result<(), ErrorKind> {
match scope {
VariableScope::Block => self
.get_current_environment()
.borrow_mut()
.create_mutable_binding(name, deletion, false),
VariableScope::Function => {
// Find the first function or global environment (from the top of the stack)
self.environments()
.find(|env| {
matches!(
env.borrow().get_environment_type(),
EnvironmentType::Function | EnvironmentType::Global
)
})
.expect("No function or global environment")
.borrow_mut()
.create_mutable_binding(name, deletion, false)
}
}
self.get_current_environment()
.borrow_mut()
.recursive_create_mutable_binding(name, deletion, scope)
}

pub fn create_immutable_binding(
Expand All @@ -154,25 +129,9 @@ impl LexicalEnvironment {
deletion: bool,
scope: VariableScope,
) -> Result<(), ErrorKind> {
match scope {
VariableScope::Block => self
.get_current_environment()
.borrow_mut()
.create_immutable_binding(name, deletion),
VariableScope::Function => {
// Find the first function or global environment (from the top of the stack)
self.environments()
.find(|env| {
matches!(
env.borrow().get_environment_type(),
EnvironmentType::Function | EnvironmentType::Global
)
})
.expect("No function or global environment")
.borrow_mut()
.create_immutable_binding(name, deletion)
}
}
self.get_current_environment()
.borrow_mut()
.recursive_create_immutable_binding(name, deletion, scope)
}

pub fn set_mutable_binding(
Expand All @@ -181,41 +140,15 @@ impl LexicalEnvironment {
value: Value,
strict: bool,
) -> Result<(), ErrorKind> {
// Find the first environment which has the given binding
let env = self
.environments()
.find(|env| env.borrow().has_binding(name));

if let Some(ref env) = env {
env
} else {
// global_env doesn't need has_binding to be satisfied in non strict mode
self.environment_stack
.get(0)
.expect("Environment stack underflow")
}
.borrow_mut()
.set_mutable_binding(name, value, strict)?;
Ok(())
self.get_current_environment()
.borrow_mut()
.recursive_set_mutable_binding(name, value, strict)
}

pub fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> {
// Find the first environment which has the given binding
let env = self
.environments()
.find(|env| env.borrow().has_binding(name));

if let Some(ref env) = env {
env
} else {
// global_env doesn't need has_binding to be satisfied in non strict mode
self.environment_stack
.get(0)
.expect("Environment stack underflow")
}
.borrow_mut()
.initialize_binding(name, value)?;
Ok(())
self.get_current_environment()
.borrow_mut()
.recursive_initialize_binding(name, value)
}

/// get_current_environment_ref is used when you only need to borrow the environment
Expand All @@ -235,20 +168,15 @@ impl LexicalEnvironment {
}

pub fn has_binding(&self, name: &str) -> bool {
self.environments()
.any(|env| env.borrow().has_binding(name))
self.get_current_environment_ref()
.borrow()
.recursive_has_binding(name)
}

pub fn get_binding_value(&self, name: &str) -> Result<Value, ErrorKind> {
self.environments()
.find(|env| env.borrow().has_binding(name))
.map(|env| env.borrow().get_binding_value(name, false))
.unwrap_or_else(|| {
Err(ErrorKind::new_reference_error(format!(
"{} is not defined",
name
)))
})
self.get_current_environment_ref()
.borrow()
.recursive_get_binding_value(name)
}
}

Expand Down
7 changes: 2 additions & 5 deletions boa/src/environment/object_environment_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,8 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord {
Value::undefined()
}

fn get_outer_environment(&self) -> Option<Environment> {
match &self.outer_env {
Some(outer) => Some(outer.clone()),
None => None,
}
fn get_outer_environment_ref(&self) -> Option<&Environment> {
self.outer_env.as_ref()
}

fn set_outer_environment(&mut self, env: Environment) {
Expand Down

0 comments on commit 33b3634

Please sign in to comment.