Commit | Line | Data |
---|---|---|
4ee7c0f2 JM |
1 | #![allow(dead_code)] |
2 | ||
8f5b0f10 JM |
3 | use std::rc::Rc; |
4 | use std::cell::RefCell; | |
5 | use std::collections::HashMap; | |
0a4d62f2 | 6 | use std::fmt; |
8f5b0f10 | 7 | |
3744d566 | 8 | use types::{MalVal,MalRet,Sym,List,_nil,list,err_string}; |
8f5b0f10 JM |
9 | |
10 | struct EnvType { | |
11 | data: HashMap<String,MalVal>, | |
12 | outer: Option<Env>, | |
13 | } | |
14 | ||
15 | pub type Env = Rc<RefCell<EnvType>>; | |
16 | ||
17 | pub fn env_new(outer: Option<Env>) -> Env { | |
18 | Rc::new(RefCell::new(EnvType{data: HashMap::new(), outer: outer})) | |
19 | } | |
20 | ||
0a4d62f2 JM |
21 | pub fn env_bind(env: &Env, |
22 | mbinds: MalVal, | |
23 | mexprs: MalVal) -> Result<Env,String> { | |
24 | let mut variadic = false; | |
25 | match *mbinds { | |
26 | List(ref binds) => { | |
27 | match *mexprs { | |
28 | List(ref exprs) => { | |
29 | let mut it = binds.iter().enumerate(); | |
30 | for (i, b) in it { | |
31 | match **b { | |
32 | Sym(ref strn) => { | |
33 | if *strn == "&".to_string() { | |
34 | variadic = true; | |
35 | break; | |
36 | } else { | |
37 | env_set(env, strn.clone(), exprs[i].clone()); | |
38 | } | |
39 | } | |
40 | _ => return Err("non-symbol bind".to_string()), | |
41 | } | |
42 | } | |
43 | if variadic { | |
44 | let (i, sym) = it.next().unwrap(); | |
45 | match **sym { | |
46 | Sym(ref s) => { | |
47 | let rest = exprs.slice(i-1,exprs.len()).to_vec(); | |
4ee7c0f2 | 48 | env_set(env, s.clone(), list(rest)); |
0a4d62f2 JM |
49 | } |
50 | _ => return Err("& bind to non-symbol".to_string()), | |
51 | } | |
52 | } | |
53 | Ok(env.clone()) | |
54 | }, | |
55 | _ => Err("exprs must be a list".to_string()), | |
56 | } | |
57 | }, | |
58 | _ => Err("binds must be a list".to_string()), | |
59 | } | |
60 | } | |
61 | ||
8f5b0f10 JM |
62 | pub fn env_find(env: Env, key: String) -> Option<Env> { |
63 | if env.borrow().data.contains_key(&key) { | |
64 | Some(env) | |
65 | } else { | |
66 | match env.borrow().outer { | |
67 | Some(ref e) => env_find(e.clone(), key), | |
68 | None => None, | |
69 | } | |
70 | } | |
71 | } | |
72 | ||
85bec8a0 JM |
73 | pub fn env_root(env: &Env) -> Env { |
74 | match env.borrow().outer { | |
75 | Some(ref ei) => env_root(ei), | |
76 | None => env.clone(), | |
77 | } | |
78 | } | |
79 | ||
8f5b0f10 JM |
80 | pub fn env_set(env: &Env, key: String, val: MalVal) { |
81 | env.borrow_mut().data.insert(key, val.clone()); | |
82 | } | |
83 | ||
84 | pub fn env_get(env: Env, key: String) -> MalRet { | |
85 | match env_find(env, key.clone()) { | |
86 | Some(e) => { | |
87 | match e.borrow().data.find_copy(&key) { | |
88 | Some(v) => Ok(v), | |
4ee7c0f2 | 89 | None => Ok(_nil()), |
8f5b0f10 JM |
90 | } |
91 | }, | |
3744d566 | 92 | None => err_string("'".to_string() + key + "' not found".to_string()), |
8f5b0f10 JM |
93 | } |
94 | } | |
95 | ||
0a4d62f2 JM |
96 | impl fmt::Show for EnvType { |
97 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
98 | match self.outer { | |
99 | Some(ref o) => write!(f, "[{}/outer:{}]", self.data, o.borrow()), | |
100 | _ => write!(f, "{}", self.data) | |
101 | } | |
102 | } | |
103 | } |