three_body_interpreter/evaluator/
env.rs1use 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 #[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}