use std::{cell::RefCell, collections::BTreeMap, ops::Deref, rc::Rc};
use crate::{
mem::{Mutator, MutatorRef},
types::Type,
value::Value,
};
pub trait Environmental<'a> {
fn env(&self) -> EnvironmentRef<'a>;
}
#[derive(Clone, Debug, PartialEq)]
pub struct EnvironmentRef<'a>(Rc<RefCell<Environment<'a>>>);
impl<'a> Deref for EnvironmentRef<'a> {
type Target = RefCell<Environment<'a>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, PartialEq)]
pub struct Environment<'a> {
scopes: Vec<Scope<'a>>,
mutator: MutatorRef<'a>,
}
impl<'a> Environment<'a> {
#[must_use]
#[inline]
pub fn new(m: MutatorRef<'a>) -> Self {
Self {
scopes: vec![BTreeMap::new()],
mutator: m,
}
}
#[must_use]
#[inline]
pub fn new_ref(m: MutatorRef<'a>) -> EnvironmentRef<'a> {
EnvironmentRef(Rc::new(RefCell::new(Self::new(m))))
}
#[must_use]
#[inline]
pub fn into_ref(self) -> EnvironmentRef<'a> {
EnvironmentRef(Rc::new(RefCell::new(self)))
}
#[must_use]
#[inline]
pub fn global_scope(&self) -> &Scope<'a> {
self.scopes.first().expect("global scope")
}
#[must_use]
#[inline]
pub fn mutator(&self) -> MutatorRef<'a> {
self.mutator.clone()
}
#[must_use]
#[inline]
pub fn top_scope(&self) -> &Scope<'a> {
self.scopes.last().expect("global scope")
}
#[must_use]
#[inline]
pub fn top_scope_mut(&mut self) -> &mut Scope<'a> {
self.scopes.last_mut().expect("global scope")
}
#[inline]
pub fn push_scope(&mut self) {
self.scopes.push(BTreeMap::new());
}
#[inline]
pub fn pop_scope(&mut self) -> Option<Scope<'a>> {
debug_assert!(self.scopes.len() > 1, "cannot pop global scope");
if self.scopes.len() > 1 {
self.scopes.pop()
} else {
None
}
}
pub fn define(
&mut self,
name: impl Into<String>,
decl_type: Type,
binding: Option<Value<'a>>,
) -> (u32, u32) {
let name = name.into();
if self.scopes.len() == 1 {
let index = u32::try_from(self.scopes[0].len()).expect("scope overflow");
self.scopes[0].insert(name, (index, decl_type, binding));
return (0, index);
}
let scope = self.top_scope_mut();
if let Some((index, var_type, var_binding)) = scope.get_mut(&name) {
*var_type = decl_type;
*var_binding = binding;
(0, *index)
} else {
let index = u32::try_from(scope.len()).expect("scope overflow");
scope.insert(name, (index, decl_type, binding));
(0, index)
}
}
pub fn lookup(&self, name: impl AsRef<str>) -> Option<Binding<'a>> {
let name = name.as_ref();
for (level, scope) in self.scopes.iter().enumerate().rev() {
if let Some((index, var_type, var_binding)) = scope.get(name) {
return Some(Binding {
level: u32::try_from(level).expect("level overflow"),
index: *index,
typedef: var_type.to_owned(),
value: var_binding.to_owned(),
});
}
}
None
}
pub fn reset(&mut self) {
self.scopes.truncate(1);
}
}
impl<'a> Default for Environment<'a> {
#[inline]
fn default() -> Self {
Self::new(Mutator::new_ref())
}
}
pub type Scope<'a> = BTreeMap<String, (u32, Type, Option<Value<'a>>)>;
#[derive(Clone, Debug, PartialEq)]
pub struct ScopeGuard<'a> {
env: EnvironmentRef<'a>,
}
impl<'a> ScopeGuard<'a> {
#[must_use]
pub fn new(env: EnvironmentRef<'a>) -> Self {
env.borrow_mut().push_scope();
Self { env }
}
}
impl<'a> Drop for ScopeGuard<'a> {
fn drop(&mut self) {
self.env.borrow_mut().pop_scope();
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Binding<'a> {
level: u32,
index: u32,
typedef: Type,
value: Option<Value<'a>>,
}
impl<'a> Binding<'a> {
#[must_use]
#[inline]
pub const fn access(&self) -> (u32, u32) {
(self.level, self.index)
}
#[must_use]
#[inline]
pub const fn level(&self) -> u32 {
self.level
}
#[must_use]
#[inline]
pub const fn index(&self) -> u32 {
self.index
}
#[must_use]
#[inline]
pub const fn typedef(&self) -> &Type {
&self.typedef
}
#[must_use]
#[inline]
pub const fn value(&self) -> Option<&Value<'a>> {
self.value.as_ref()
}
}