brooks_lib/environment/
scope.rs1use std::{collections::HashMap, fmt::Debug, ops::Add};
19
20#[derive(Debug, Clone, Default)]
21pub struct Scope<I: Clone + Default> {
22 pub items: HashMap<String, I>,
23}
24
25impl<I: Clone + Default> Scope<I> {
26 pub fn lookup(&self, id: &str) -> Option<I> {
27 self.items.get(id).cloned()
28 }
29 pub fn insert(&self, id: &str, value: I) -> Self {
30 let mut next = self.items.clone();
31 next.insert(id.to_string(), value);
32 Self { items: next }
33 }
34}
35
36impl<I: Clone + Default> Add for &Scope<I> {
37 type Output = Scope<I>;
38
39 fn add(self, rhs: Self) -> Self::Output {
40 let mut ns = Scope::<I> {
41 items: HashMap::new(),
42 };
43 for (k, v) in &self.items {
44 ns = ns.insert(k, v.clone());
45 }
46 for (k, v) in &rhs.items {
47 ns = ns.insert(k, v.clone());
48 }
49 ns
50 }
51}
52
53#[derive(Debug, Clone)]
54pub struct Scopes<I: Clone + Default> {
55 pub scopes: Vec<Scope<I>>,
56}
57
58impl<I: Clone + Default> From<Scope<I>> for Scopes<I> {
59 fn from(value: Scope<I>) -> Self {
60 Scopes {
61 scopes: vec![value],
62 }
63 }
64}
65
66impl<I: Clone + Default> Scopes<I> {
67 pub fn lookup(&self, id: &str) -> Option<I> {
68 for scope in self.scopes.iter().rev() {
69 if let Some(id) = scope.lookup(id) {
70 return Some(id);
71 }
72 }
73 None
74 }
75
76 pub fn insert(&self, id: &str, value: I) -> Self {
77 let updated_scope = self.scopes[0].insert(id, value);
78
79 let mut next = self.scopes.clone();
80 next[0] = updated_scope;
81
82 Self { scopes: next }
83 }
84
85 pub fn leave(&self) -> Scopes<I> {
86 let mut next = self.scopes.clone();
87 next.pop();
88 Self { scopes: next }
89 }
90
91 pub fn enter(&self) -> Scopes<I> {
92 let mut next = self.scopes.clone();
93 next.push(Scope::default());
94 Self { scopes: next }
95 }
96
97 pub fn enter_scope(&self, entering: Scope<I>) -> Scopes<I> {
98 let mut next = self.scopes.clone();
99 next.push(entering);
100 Self { scopes: next }
101 }
102
103 pub fn current(&self) -> &Scope<I> {
104 &self.scopes[0]
105 }
106}
107
108impl<I: Clone + Default> Default for Scopes<I> {
109 fn default() -> Self {
110 Self {
111 scopes: vec![Scope::default()],
112 }
113 }
114}
115
116#[cfg(test)]
117mod scope_tests {
118 use std::assert_matches;
119 use std::collections::HashMap;
120
121 use crate::environment::scope::Scope;
122
123 #[test]
124 fn test_operator_plus() {
125 let mut s1 = Scope::<i8> {
126 items: HashMap::new(),
127 };
128 s1 = s1.insert("x", 5);
129 let mut s2 = Scope::<i8> {
130 items: HashMap::new(),
131 };
132 s2 = s2.insert("y", 4);
133
134 let s3 = &s1 + &s2;
135
136 assert_matches!(s3.lookup("y"), Some(4));
137 assert_matches!(s3.lookup("x"), Some(5));
138 }
139}