tlisp 0.0.2

Lisp interpreter in Rust
Documentation
mod list;
mod string;

use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};

use crate::{environment::Environment, eval::eval_object, object::Object};

pub type RuntimeFn = dyn Fn(&Vec<Object>, &mut Rc<RefCell<Environment>>) -> Result<Object, String>;

#[derive(Clone)]
pub struct Runtime {
  methods: Rc<HashMap<String, Rc<RuntimeFn>>>,
}

impl Debug for Runtime {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    let methods_str = self
      .methods
      .iter()
      .map(|(k, _)| k.clone())
      .collect::<Vec<String>>()
      .join(", ");

    write!(f, "Runtime {{ methods: {} }}", methods_str)
  }
}

fn debug(args: &Vec<Object>, _env: &mut Rc<RefCell<Environment>>) -> Result<Object, String> {
  println!("{:?}", args);

  Ok(Object::Void)
}

fn print(args: &Vec<Object>, _env: &mut Rc<RefCell<Environment>>) -> Result<Object, String> {
  let mut result = String::new();

  for arg in args {
    result.push_str(&arg.to_string());
  }

  println!("{}", result);

  Ok(Object::Void)
}

fn eval_eval(args: &Vec<Object>, env: &mut Rc<RefCell<Environment>>) -> Result<Object, String> {
  let param = args.get(0);

  if param.is_none() {
    return Ok(Object::Void);
  }

  let param = param.unwrap();

  let unquoted = match param {
    Object::Quote(o) => &o,
    o => o,
  };

  let unquoted = match unquoted {
    Object::List(list) => {
      let mut unquoted_params = Vec::new();
      for obj in list {
        let result = match obj {
          Object::Quote(o) => &o,
          o => o,
        };

        unquoted_params.push(result.clone());
      }
      Object::List(unquoted_params)
    }
    o => o.clone(),
  };

  eval_object(&unquoted, env)
}

impl Runtime {
  pub fn new() -> Runtime {
    let mut methods: HashMap<String, Rc<RuntimeFn>> = HashMap::new();

    methods.insert("debug!".to_string(), Rc::new(debug));
    methods.insert("print!".to_string(), Rc::new(print));
    methods.insert("eval".to_string(), Rc::new(eval_eval));

    list::load_list_fns(&mut methods);
    string::load_string_fns(&mut methods);

    Runtime {
      methods: Rc::new(methods),
    }
  }

  pub fn get_method(&self, name: &str) -> Option<&Rc<RuntimeFn>> {
    self.methods.get(name)
  }
}