mimium_lang/utils/
environment.rs1use std::collections::LinkedList;
2
3use crate::interner::Symbol;
4
5type EnvInner<T> = LinkedList<Vec<(Symbol, T)>>;
6
7#[derive(Clone, Debug, PartialEq)]
12pub struct Environment<T>(pub EnvInner<T>);
13
14#[derive(Clone, Debug, PartialEq)]
16pub enum LookupRes<T: Clone> {
17 Local(T),
19 UpValue(usize, T),
22 Global(T),
24 None,
26}
27impl<T: Clone> Default for Environment<T> {
28 fn default() -> Self {
29 Self(EnvInner::new())
30 }
31}
32impl<T: Clone> Environment<T> {
33 pub fn new() -> Self {
35 Self(EnvInner::new())
36 }
37
38 pub fn is_global(&self) -> bool {
40 self.0.len() <= 1
41 }
42
43 pub fn extend(&mut self) {
45 self.0.push_front(Vec::new());
46 }
47
48 pub fn to_outer(&mut self) {
50 let _ = self.0.pop_front();
51 }
52
53 pub fn add_bind(&mut self, binds: &[(Symbol, T)]) {
55 assert!(!self.0.is_empty());
56 self.0.front_mut().unwrap().extend_from_slice(binds);
57 }
58
59 pub fn lookup_cls(&self, name: &Symbol) -> LookupRes<&T> {
61 match self
62 .0
63 .iter()
64 .enumerate()
65 .find(|(_level, vec)| vec.iter().any(|(n, _)| n == name))
66 .and_then(|(level, vec)| {
67 vec.iter()
68 .rfind(|(n, _)| n == name)
69 .map(|(_, v)| (level, v))
70 }) {
71 None => LookupRes::None,
72 Some((level, e)) if level >= self.0.len() - 1 => LookupRes::Global(e),
73 Some((0, e)) if self.0.len() <= 1 => LookupRes::Global(e),
74 Some((0, e)) => LookupRes::Local(e),
75 Some((level, e)) => LookupRes::UpValue(level, e),
76 }
77 }
78 pub fn lookup(&self, name: &Symbol) -> Option<&T> {
83 match self.lookup_cls(name) {
84 LookupRes::None => None,
85 LookupRes::Global(e) | LookupRes::Local(e) | LookupRes::UpValue(_, e) => Some(e),
86 }
87 }
88}