env.rs 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. use std::cell::RefCell;
  2. use std::collections::HashMap;
  3. use std::rc::Rc;
  4. // use fnv::FnvHashMap;
  5. use crate::types::MalErr::ErrString;
  6. use crate::types::MalVal::{List, Nil, Sym, Vector};
  7. use crate::types::{error, MalErr, MalRet, MalVal};
  8. #[derive(Debug)]
  9. pub struct EnvStruct {
  10. data: RefCell<HashMap<String, MalVal>>,
  11. pub outer: Option<Env>,
  12. }
  13. pub type Env = Rc<EnvStruct>;
  14. // TODO: it would be nice to use impl here but it doesn't work on
  15. // a deftype (i.e. Env)
  16. pub fn env_new(outer: Option<Env>) -> Env {
  17. Rc::new(EnvStruct {
  18. data: RefCell::new(HashMap::default()),
  19. outer: outer,
  20. })
  21. }
  22. // TODO: mbinds and exprs as & types
  23. pub fn env_bind(outer: Option<Env>, mbinds: MalVal, exprs: Vec<MalVal>) -> Result<Env, MalErr> {
  24. let env = env_new(outer);
  25. match mbinds {
  26. List(binds, _) | Vector(binds, _) => {
  27. for (i, b) in binds.iter().enumerate() {
  28. match b {
  29. Sym(s) if s == "&" => {
  30. env_set(&env, binds[i + 1].clone(), list!(exprs[i..].to_vec()))?;
  31. break;
  32. }
  33. _ => {
  34. env_set(&env, b.clone(), exprs[i].clone())?;
  35. }
  36. }
  37. }
  38. Ok(env)
  39. }
  40. _ => Err(ErrString("env_bind binds not List/Vector".to_string())),
  41. }
  42. }
  43. pub fn env_find(env: &Env, key: &str) -> Option<Env> {
  44. match (env.data.borrow().contains_key(key), env.outer.clone()) {
  45. (true, _) => Some(env.clone()),
  46. (false, Some(o)) => env_find(&o, key),
  47. _ => None,
  48. }
  49. }
  50. pub fn env_get(env: &Env, key: &MalVal) -> MalRet {
  51. match key {
  52. Sym(ref s) => match env_find(env, s) {
  53. Some(e) => Ok(e
  54. .data
  55. .borrow()
  56. .get(s)
  57. .ok_or(ErrString(format!("'{}' not found", s)))?
  58. .clone()),
  59. _ => error(&format!("'{}' not found", s)),
  60. },
  61. _ => error("Env.get called with non-Str"),
  62. }
  63. }
  64. pub fn env_set(env: &Env, key: MalVal, val: MalVal) -> MalRet {
  65. match key {
  66. Sym(ref s) => {
  67. env.data.borrow_mut().insert(s.to_string(), val.clone());
  68. Ok(val)
  69. }
  70. _ => error("Env.set called with non-Str"),
  71. }
  72. }
  73. pub fn env_sets(env: &Env, key: &str, val: MalVal) {
  74. env.data.borrow_mut().insert(key.to_string(), val);
  75. }