use std::collections::HashMap;
use crate::ast::Pass;
use crate::source::token::Span;
#[derive(Clone, Default)]
pub(super) struct Var {
pub lent: Option<Pass>,
pub moved: Option<Span>,
pub unset: Option<Span>,
}
impl Var {
pub fn unset(at: Span) -> Self {
Var {
unset: Some(at),
..Var::default()
}
}
}
#[derive(Clone)]
pub(super) struct State {
scopes: Vec<HashMap<String, Var>>,
pub dead: bool,
}
impl State {
pub fn new() -> Self {
State {
scopes: vec![HashMap::new()],
dead: false,
}
}
pub fn push(&mut self) {
self.scopes.push(HashMap::new());
}
pub fn pop(&mut self) {
self.scopes.pop();
}
pub fn declare(&mut self, name: &str, var: Var) {
if let Some(scope) = self.scopes.last_mut() {
scope.insert(name.to_string(), var);
}
}
pub fn get(&self, name: &str) -> Option<&Var> {
self.scopes.iter().rev().find_map(|s| s.get(name))
}
pub fn get_mut(&mut self, name: &str) -> Option<&mut Var> {
self.scopes.iter_mut().rev().find_map(|s| s.get_mut(name))
}
pub fn join(self, other: State) -> State {
if self.dead {
return other;
}
if other.dead {
return self;
}
let scopes = self
.scopes
.into_iter()
.zip(other.scopes)
.map(|(mut mine, theirs)| {
for (name, var) in theirs {
if let Some(m) = mine.get_mut(&name) {
m.moved = m.moved.or(var.moved);
m.unset = m.unset.or(var.unset);
}
}
mine
})
.collect();
State {
scopes,
dead: false,
}
}
}