Skip to main content

three_body_interpreter/evaluator/
env.rs

1use crate::evaluator::object::Object;
2use std::cell::RefCell;
3use std::collections::HashMap;
4use std::rc::Rc;
5
6#[derive(PartialEq, Clone, Debug)]
7struct VariableStatus {
8    constant: bool,
9}
10
11#[derive(PartialEq, Clone, Debug)]
12pub struct Env {
13    pub identifiers: HashMap<String, Object>,
14    variables_status: HashMap<String, VariableStatus>,
15    outer: Option<Rc<RefCell<Env>>>,
16}
17
18#[derive(PartialEq, Clone, Debug)]
19pub enum UpdateInfo {
20    ConstantForbidden,
21    NoIdentifier,
22    Succeed,
23}
24
25#[derive(PartialEq, Clone, Debug)]
26pub enum CheckInnerInfo {
27    ConstantExist,
28    VariableExist,
29    NoIdentifier,
30}
31
32impl Env {
33    pub fn new() -> Self {
34        Env {
35            identifiers: HashMap::new(),
36            variables_status: HashMap::new(),
37            outer: None,
38        }
39    }
40
41    pub fn from(builtins: HashMap<String, Object>) -> Self {
42        Env {
43            identifiers: builtins,
44            variables_status: HashMap::new(),
45            outer: None,
46        }
47    }
48
49    pub fn new_with_outer(outer: Rc<RefCell<Env>>) -> Self {
50        Env {
51            identifiers: HashMap::new(),
52            variables_status: HashMap::new(),
53            outer: Some(outer),
54        }
55    }
56
57    pub fn check_inner(&mut self, name: String) -> CheckInnerInfo {
58        match self.identifiers.contains_key(&name) {
59            true => {
60                if self.is_constant(name.clone()) {
61                    return CheckInnerInfo::ConstantExist;
62                }
63                CheckInnerInfo::VariableExist
64            },
65            false => {
66                CheckInnerInfo::NoIdentifier
67            }
68        }
69    }
70
71    pub fn set(&mut self, name: String, value: Object) {
72        self.identifiers.insert(name, value.clone());
73    }
74
75    pub fn update(&mut self, name: String, value: Object) -> UpdateInfo {
76        match self.identifiers.contains_key(&name) {
77            true => {
78                if self.is_constant(name.clone()) {
79                    return UpdateInfo::ConstantForbidden;
80                }
81                self.identifiers.insert(name.clone(), value.clone());
82                return UpdateInfo::Succeed;
83            },
84            false => {
85                match self.outer {
86                    Some(ref outer) => outer.borrow_mut().update(name, value),
87                    None => UpdateInfo::NoIdentifier,
88                }
89            }
90        }
91    }
92
93    pub fn get(&mut self, name: String) -> Option<Object> {
94        match self.identifiers.get(&name) {
95            Some(value) => Some(value.clone()),
96            None => match self.outer {
97                Some(ref outer) => outer.borrow_mut().get(name),
98                None => None,
99            },
100        }
101    }
102}
103
104impl Env {
105    pub fn constant(&mut self, name: String) {
106        match self.variables_status.get_mut(&name) {
107            Some(variable_status) => {
108                variable_status.constant = true;
109            }
110            None => {
111                self.variables_status
112                    .insert(name, VariableStatus { constant: true });
113            }
114        }
115    }
116
117    pub fn is_constant(&mut self, name: String) -> bool {
118        match self.variables_status.get(&name) {
119            Some(variable_status) => variable_status.constant == true,
120            None => false,
121        }
122    }
123}
124
125
126#[cfg(test)]
127mod tests {
128    use std::borrow::BorrowMut;
129
130    use super::*;
131    use crate::evaluator::object::*;
132
133    #[test]
134    fn test_env_new() {
135        let env = Env::new();
136        assert_eq!(env.identifiers.len(), 0);
137        assert_eq!(env.outer, None);
138    }
139
140    #[test]
141    fn test_env_from() {
142        let mut store = HashMap::new();
143        store.insert("key".to_string(), Object::Int(1));
144        let env = Env::from(store);
145        assert_eq!(env.identifiers.len(), 1);
146        assert_eq!(env.outer, None);
147    }
148
149    #[test]
150    fn test_env_new_with_outer() {
151        let outer = Rc::new(RefCell::new(Env::new()));
152        let env = Env::new_with_outer(outer.clone());
153        assert_eq!(env.identifiers.len(), 0);
154        assert_eq!(env.outer, Some(outer));
155    }
156
157    #[test]
158    fn test_env_get() {
159        let mut env = Env::new();
160        env.set("key".to_string(), Object::Int(1));
161        assert_eq!(env.get("key".to_string()), Some(Object::Int(1)));
162    }
163
164    #[test]
165    fn test_env_set() {
166        let mut env = Env::new();
167        env.set("key".to_string(), Object::Int(1));
168        assert_eq!(env.identifiers.get("key"), Some(&Object::Int(1)));
169    }
170
171    // self cases
172
173    #[test]
174    fn test_update_succeed() {
175        let mut env = Env::new();
176        env.set("key".to_string(), Object::Int(1));
177        assert_eq!(env.update("key".to_string(), Object::Int(2)), UpdateInfo::Succeed);
178    }
179
180    #[test]
181    fn test_update_forbidden() {
182        let mut env = Env::new();
183        env.set("key".to_string(), Object::Int(1));
184        env.constant("key".to_string());
185        assert_eq!(env.update("key".to_string(), Object::Int(2)), UpdateInfo::ConstantForbidden);
186    }
187
188    #[test]
189    fn test_update_no_identifier() {
190        let mut env = Env::new();
191        assert_eq!(env.update("key".to_string(), Object::Int(2)), UpdateInfo::NoIdentifier);
192    }
193
194    #[test]
195    fn test_update_out_identifier() {
196        let global = Rc::new(RefCell::new(Env::new()));
197        let outer = Rc::new(RefCell::new(Env::new_with_outer(global.clone())));
198        let mut env = Env::new_with_outer(outer.clone());
199        outer.as_ref().borrow_mut().set("key".to_string(), Object::Int(2));
200        assert_eq!(outer.as_ref().borrow_mut().update("key".to_string(), Object::Int(2)), UpdateInfo::Succeed);
201        assert_eq!(env.update("key".to_string(), Object::Int(2)), UpdateInfo::Succeed);
202        assert_eq!(global.as_ref().borrow_mut().update("key".to_string(), Object::Int(2)), UpdateInfo::NoIdentifier);
203    }
204}