blots_core/
environment.rs1use crate::values::Value;
2use std::cell::RefCell;
3use std::collections::HashMap;
4use std::rc::Rc;
5
6#[derive(Debug)]
7enum LocalBindings {
8 Owned(RefCell<HashMap<String, Value>>),
9 Shared(Rc<HashMap<String, Value>>),
10}
11
12#[derive(Debug)]
18pub struct Environment {
19 local: LocalBindings,
21 parent: Option<Rc<Environment>>,
23}
24
25impl Environment {
26 pub fn new() -> Self {
28 Environment {
29 local: LocalBindings::Owned(RefCell::new(HashMap::new())),
30 parent: None,
31 }
32 }
33
34 pub fn with_bindings(bindings: HashMap<String, Value>) -> Self {
36 Environment {
37 local: LocalBindings::Owned(RefCell::new(bindings)),
38 parent: None,
39 }
40 }
41
42 pub fn extend(parent: Rc<Environment>) -> Self {
44 Environment {
45 local: LocalBindings::Owned(RefCell::new(HashMap::new())),
46 parent: Some(parent),
47 }
48 }
49
50 pub fn extend_with(parent: Rc<Environment>, local: HashMap<String, Value>) -> Self {
52 Environment {
53 local: LocalBindings::Owned(RefCell::new(local)),
54 parent: Some(parent),
55 }
56 }
57
58 pub fn extend_shared(parent: Rc<Environment>, local: Rc<HashMap<String, Value>>) -> Self {
60 Environment {
61 local: LocalBindings::Shared(local),
62 parent: Some(parent),
63 }
64 }
65
66 pub fn get(&self, key: &str) -> Option<Value> {
68 let local_value = match &self.local {
70 LocalBindings::Owned(map) => map.borrow().get(key).copied(),
71 LocalBindings::Shared(map) => map.get(key).copied(),
72 };
73 if let Some(value) = local_value {
74 return Some(value);
75 }
76 if let Some(parent) = &self.parent {
78 return parent.get(key);
79 }
80 None
81 }
82
83 pub fn insert(&self, key: String, value: Value) {
85 match &self.local {
86 LocalBindings::Owned(map) => {
87 map.borrow_mut().insert(key, value);
88 }
89 LocalBindings::Shared(_) => {
90 panic!("cannot insert into shared environment");
91 }
92 }
93 }
94
95 pub fn contains_key(&self, key: &str) -> bool {
97 let contains_local = match &self.local {
98 LocalBindings::Owned(map) => map.borrow().contains_key(key),
99 LocalBindings::Shared(map) => map.contains_key(key),
100 };
101 if contains_local {
102 return true;
103 }
104 if let Some(parent) = &self.parent {
105 return parent.contains_key(key);
106 }
107 false
108 }
109
110 pub fn contains_key_local(&self, key: &str) -> bool {
112 match &self.local {
113 LocalBindings::Owned(map) => map.borrow().contains_key(key),
114 LocalBindings::Shared(map) => map.contains_key(key),
115 }
116 }
117}
118
119impl Default for Environment {
120 fn default() -> Self {
121 Self::new()
122 }
123}
124
125impl Clone for Environment {
126 fn clone(&self) -> Self {
127 Environment {
130 local: LocalBindings::Owned(RefCell::new(self.flatten())),
131 parent: None,
132 }
133 }
134}
135
136impl Environment {
137 pub fn flatten(&self) -> HashMap<String, Value> {
140 let mut result = HashMap::new();
141 self.flatten_into(&mut result);
142 result
143 }
144
145 fn flatten_into(&self, result: &mut HashMap<String, Value>) {
146 if let Some(parent) = &self.parent {
148 parent.flatten_into(result);
149 }
150 match &self.local {
152 LocalBindings::Owned(map) => {
153 for (key, value) in map.borrow().iter() {
154 result.insert(key.clone(), *value);
155 }
156 }
157 LocalBindings::Shared(map) => {
158 for (key, value) in map.iter() {
159 result.insert(key.clone(), *value);
160 }
161 }
162 }
163 }
164
165 pub fn iter(&self) -> impl Iterator<Item = (String, Value)> {
168 self.flatten().into_iter()
169 }
170
171 pub fn keys(&self) -> impl Iterator<Item = String> {
174 self.flatten().into_keys()
175 }
176}