mod function;
mod global;
mod lexical;
mod module;
pub(crate) use function::{FunctionEnvironment, FunctionSlots, ThisBindingStatus};
pub(crate) use global::GlobalEnvironment;
pub(crate) use lexical::LexicalEnvironment;
pub(crate) use module::ModuleEnvironment;
use crate::{JsResult, JsValue};
use boa_gc::{Finalize, Trace};
use std::cell::Cell;
#[derive(Debug, Trace, Finalize)]
pub(crate) struct DeclarativeEnvironment {
kind: DeclarativeEnvironmentKind,
#[unsafe_ignore_trace]
poisoned: Cell<bool>,
with: bool,
}
impl DeclarativeEnvironment {
pub(crate) fn global() -> Self {
Self {
kind: DeclarativeEnvironmentKind::Global(GlobalEnvironment::new()),
poisoned: Cell::new(false),
with: false,
}
}
pub(crate) fn new(kind: DeclarativeEnvironmentKind, poisoned: bool, with: bool) -> Self {
Self {
kind,
poisoned: Cell::new(poisoned),
with,
}
}
pub(crate) const fn kind(&self) -> &DeclarativeEnvironmentKind {
&self.kind
}
pub(crate) fn is_function(&self) -> bool {
matches!(self.kind(), DeclarativeEnvironmentKind::Function(_))
}
#[track_caller]
pub(crate) fn get(&self, index: u32) -> Option<JsValue> {
self.kind.get(index)
}
#[track_caller]
pub(crate) fn set(&self, index: u32, value: JsValue) {
self.kind.set(index, value);
}
#[track_caller]
pub(crate) fn delete_binding(&self, index: u32) -> bool {
self.kind.delete_binding(index)
}
#[track_caller]
pub(crate) fn is_deleted_binding(&self, index: u32) -> bool {
self.kind.is_deleted_binding(index)
}
#[track_caller]
pub(crate) fn restore_deleted_binding(&self, index: u32) {
self.kind.restore_deleted_binding(index);
}
pub(crate) fn get_this_binding(&self) -> JsResult<Option<JsValue>> {
self.kind.get_this_binding()
}
pub(crate) fn has_this_binding(&self) -> bool {
self.kind.has_this_binding()
}
pub(crate) fn poisoned(&self) -> bool {
self.poisoned.get()
}
pub(crate) fn with(&self) -> bool {
self.with
}
pub(crate) fn poison(&self) {
self.poisoned.set(true);
}
pub(crate) fn extend_from_compile(&self) {
if let Some(env) = self.kind().as_function() {
env.extend_from_compile();
}
}
}
#[derive(Debug, Trace, Finalize)]
pub(crate) enum DeclarativeEnvironmentKind {
Lexical(LexicalEnvironment),
Global(GlobalEnvironment),
Function(FunctionEnvironment),
Module(ModuleEnvironment),
}
impl DeclarativeEnvironmentKind {
pub(crate) const fn as_function(&self) -> Option<&FunctionEnvironment> {
if let Self::Function(fun) = &self {
Some(fun)
} else {
None
}
}
pub(crate) const fn as_global(&self) -> Option<&GlobalEnvironment> {
if let Self::Global(fun) = &self {
Some(fun)
} else {
None
}
}
pub(crate) const fn as_module(&self) -> Option<&ModuleEnvironment> {
if let Self::Module(module) = &self {
Some(module)
} else {
None
}
}
#[track_caller]
pub(crate) fn get(&self, index: u32) -> Option<JsValue> {
match self {
Self::Lexical(inner) => inner.get(index),
Self::Global(inner) => inner.get(index),
Self::Function(inner) => inner.get(index),
Self::Module(inner) => inner.get(index),
}
}
#[track_caller]
pub(crate) fn set(&self, index: u32, value: JsValue) {
match self {
Self::Lexical(inner) => inner.set(index, value),
Self::Global(inner) => inner.set(index, value),
Self::Function(inner) => inner.set(index, value),
Self::Module(inner) => inner.set(index, value),
}
}
#[track_caller]
pub(crate) fn delete_binding(&self, index: u32) -> bool {
match self {
Self::Function(inner) => inner.delete_binding(index),
Self::Lexical(_) | Self::Global(_) | Self::Module(_) => false,
}
}
#[track_caller]
pub(crate) fn is_deleted_binding(&self, index: u32) -> bool {
match self {
Self::Function(inner) => inner.is_deleted_binding(index),
Self::Lexical(_) | Self::Global(_) | Self::Module(_) => false,
}
}
#[track_caller]
pub(crate) fn restore_deleted_binding(&self, index: u32) {
if let Self::Function(inner) = self {
inner.restore_deleted_binding(index);
}
}
pub(crate) fn get_this_binding(&self) -> JsResult<Option<JsValue>> {
match self {
Self::Lexical(_) | Self::Global(_) => Ok(None),
Self::Function(f) => f.get_this_binding(),
Self::Module(_) => Ok(Some(JsValue::undefined())),
}
}
pub(crate) fn has_this_binding(&self) -> bool {
match self {
Self::Lexical(_) => false,
Self::Function(f) => f.has_this_binding(),
Self::Global(_) | Self::Module(_) => true,
}
}
}