tlisp 0.0.2

Lisp interpreter in Rust
Documentation
use crate::{object::Object, runtime};
use std::{cell::RefCell, collections::HashMap, fmt, rc::Rc};

#[derive(Debug)]
pub struct Environment {
  parent: Option<Rc<RefCell<Environment>>>,
  vars: HashMap<String, Object>,
  runtime: runtime::Runtime,
}

impl PartialEq for Environment {
  fn eq(&self, other: &Self) -> bool {
    self.vars == other.vars
  }
}

impl Environment {
  pub fn new(runtime: runtime::Runtime) -> Self {
    Environment {
      parent: None,
      vars: HashMap::new(),
      runtime,
    }
  }

  pub fn extend(parent: Rc<RefCell<Self>>) -> Environment {
    let runtime = parent.borrow().runtime.clone();
    Environment {
      vars: HashMap::new(),
      parent: Some(parent),
      runtime,
    }
  }

  pub fn get_runtime_fn(&self, name: &str) -> Option<Rc<runtime::RuntimeFn>> {
    let runtime = self.runtime.clone();

    match runtime.get_method(name) {
      Some(f) => Some(f.clone()),
      None => None,
    }
  }

  pub fn get(&self, name: &str) -> Option<Object> {
    match self.vars.get(name) {
      Some(value) => Some(value.clone()),
      None => self.parent.as_ref().and_then(|o| o.borrow().get(name)),
    }
  }

  pub fn set(&mut self, name: &str, val: Object) {
    self.vars.insert(name.to_string(), val);
  }

  pub fn update(&mut self, data: Rc<RefCell<Self>>) {
    self.vars.extend(
      data
        .borrow()
        .vars
        .iter()
        .map(|(k, v)| (k.clone(), v.clone())),
    );
  }
}

impl fmt::Display for Environment {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let mut vars_str = String::new();

    for (k, v) in self.vars.iter() {
      vars_str.push_str(&format!("{}: {}\n", k, v));
    }

    let _ = match self.parent {
      Some(ref parent) => {
        vars_str.push_str(&format!("parent: {}\n", parent.borrow()));
      }
      None => {
        vars_str.push_str("parent: None\n");
      }
    };

    write!(f, "{}", vars_str)
  }
}