1use crate::runtime::value::Value;
2use std::{cell::RefCell, collections::HashMap, rc::Rc};
3
4#[derive(Clone, Debug)]
5pub struct Env {
6 pub values: HashMap<String, Value>,
7 pub exports: HashMap<String, Value>,
8 pub parent: Option<Rc<RefCell<Env>>>,
9}
10
11impl Env {
12 #[inline(always)]
13 pub fn new() -> Self {
14 Self {
15 values: HashMap::new(),
16 exports: HashMap::new(),
17 parent: None,
18 }
19 }
20
21 #[inline(always)]
22 pub fn new_with_parent(parent: Option<Rc<RefCell<Env>>>) -> Self {
23 Self {
24 values: HashMap::new(),
25 exports: HashMap::new(),
26 parent,
27 }
28 }
29
30 pub fn assign(&mut self, name: &str, val: Value) -> Result<(), String> {
31 if self.values.contains_key(name) {
32 self.values.insert(name.to_string(), val);
33
34 Ok(())
35 } else if let Some(parent) = &self.parent {
36 parent.borrow_mut().assign(name, val)
37 } else {
38 Err(format!("undefined variable `{name}`"))
39 }
40 }
41
42 #[inline(always)]
43 pub fn define(&mut self, name: String, val: Value) {
44 self.values.insert(name, val);
45 }
46
47 #[inline(always)]
48 pub fn get(&self, name: &str) -> Option<Value> {
49 if let Some(v) = self.values.get(name) {
50 Some(v.clone())
51 } else if let Some(parent) = &self.parent {
52 parent.borrow().get(name)
53 } else {
54 None
55 }
56 }
57
58 #[inline(always)]
59 pub fn define_export(&mut self, name: String, value: Value) {
60 self.exports.insert(name.clone(), value.clone());
61 self.values.insert(name, value);
62 }
63
64 #[inline(always)]
65 pub fn exported_values(&self) -> HashMap<String, Value> {
66 self.exports.clone()
67 }
68}