monkey_rs/eval/
environment.rs

1//! This module defines a programming environment within Monkey.
2use std::cell::RefCell;
3use std::collections::HashMap;
4use std::rc::Rc;
5
6use crate::eval::object::Object;
7
8/// Type alias for shared, interior-mutable environment.
9pub type Env = Rc<RefCell<Environment>>;
10
11/// A wrapper around the stored values obtained during evaluation.
12#[derive(Debug, Default, PartialEq, Eq)]
13pub struct Environment {
14    store: HashMap<String, Rc<Object>>,
15    /// Outer/ enclosing environment that is being extended by the Environment
16    /// instance.
17    outer: Option<Env>,
18}
19
20impl Environment {
21    /// Construct a new blank environment.
22    pub fn new() -> Environment {
23        Environment {
24            store: HashMap::new(),
25            outer: None,
26        }
27    }
28
29    /// Constructs a new enclosed environment within the outer environment.
30    pub fn new_enclosed_environment(outer: &Env) -> Environment {
31        Environment {
32            store: HashMap::new(),
33            outer: Some(Rc::clone(outer)),
34        }
35    }
36
37    /// Retrieves the value associated with a key, if it exists.
38    pub fn get(&self, name: &str) -> Option<Rc<Object>> {
39        match self.store.get(name) {
40            Some(obj) => Some(Rc::clone(obj)),
41            None => {
42                // Check the enclosing environment as well, if it exists.
43                if let Some(outer) = &self.outer {
44                    outer.borrow().get(name)
45                } else {
46                    None
47                }
48            }
49        }
50    }
51
52    /// Sets the value for a given key. If the key is already present in the
53    /// environment, its value is updated.
54    pub fn set(&mut self, name: &str, val: Rc<Object>) {
55        self.store.insert(name.to_string(), val);
56    }
57}