use super::*;
use crate::property::PropertyDescriptor;
use crate::{
environment::{
environment_record_trait::EnvironmentRecordTrait,
lexical_environment::{Environment, EnvironmentType},
},
gc::{Finalize, Trace},
property::{Attribute, DataDescriptor},
Value,
};
#[derive(Debug, Trace, Finalize, Clone)]
pub struct ObjectEnvironmentRecord {
pub bindings: Value,
pub with_environment: bool,
pub outer_env: Option<Environment>,
}
impl EnvironmentRecordTrait for ObjectEnvironmentRecord {
fn has_binding(&self, name: &str) -> bool {
if self.bindings.has_field(name) {
if self.with_environment {
}
true
} else {
false
}
}
fn create_mutable_binding(
&mut self,
name: String,
deletion: bool,
_allow_name_reuse: bool,
) -> Result<(), ErrorKind> {
let bindings = &mut self.bindings;
let mut prop = DataDescriptor::new(
Value::undefined(),
Attribute::WRITABLE | Attribute::ENUMERABLE,
);
prop.set_configurable(deletion);
bindings.set_property(name, prop);
Ok(())
}
fn create_immutable_binding(&mut self, _name: String, _strict: bool) -> Result<(), ErrorKind> {
Ok(())
}
fn initialize_binding(&mut self, name: &str, value: Value) -> Result<(), ErrorKind> {
debug_assert!(self.has_binding(&name));
self.set_mutable_binding(name, value, false)
}
fn set_mutable_binding(
&mut self,
name: &str,
value: Value,
strict: bool,
) -> Result<(), ErrorKind> {
debug_assert!(value.is_object() || value.is_function());
let mut property = DataDescriptor::new(value, Attribute::ENUMERABLE);
property.set_configurable(strict);
self.bindings
.as_object()
.expect("binding object")
.insert(name, property);
Ok(())
}
fn get_binding_value(&self, name: &str, strict: bool) -> Result<Value, ErrorKind> {
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
)))
} else {
Ok(Value::undefined())
}
}
fn delete_binding(&mut self, name: &str) -> bool {
self.bindings.remove_property(name);
true
}
fn has_this_binding(&self) -> bool {
false
}
fn get_this_binding(&self) -> Result<Value, ErrorKind> {
Ok(Value::undefined())
}
fn has_super_binding(&self) -> bool {
false
}
fn with_base_object(&self) -> Value {
if self.with_environment {
return self.bindings.clone();
}
Value::undefined()
}
fn get_outer_environment(&self) -> Option<Environment> {
match &self.outer_env {
Some(outer) => Some(outer.clone()),
None => None,
}
}
fn set_outer_environment(&mut self, env: Environment) {
self.outer_env = Some(env);
}
fn get_environment_type(&self) -> EnvironmentType {
EnvironmentType::Function
}
fn get_global_object(&self) -> Option<Value> {
if let Some(outer) = &self.outer_env {
outer.borrow().get_global_object()
} else {
None
}
}
}