use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
use super::{Cont, Env, Ns, Primitive, Proc, Result, SExp};
mod base;
mod core;
mod math;
mod write;
pub struct Context {
core: Ns,
cont: Rc<RefCell<Cont>>,
pub lang: Ns,
out: Option<String>,
}
impl Default for Context {
fn default() -> Self {
Self {
core: Self::core(),
cont: Cont::default().into_rc(),
lang: Ns::new(),
out: None,
}
}
}
impl Context {
pub fn push(&mut self) {
self.cont.borrow_mut().push();
}
pub fn pop(&mut self) {
self.cont.borrow_mut().pop();
}
pub fn define(&mut self, key: &str, value: SExp) {
self.cont.borrow().env().define(key, value);
}
#[must_use]
pub fn get(&self, key: &str) -> Option<SExp> {
if let Some(exp) = self.core.get(key) {
return Some(exp.clone());
}
if let Some(exp) = self.cont.borrow().env().get(key) {
return Some(exp);
}
if let Some(exp) = self.lang.get(key) {
return Some(exp.clone());
}
None
}
pub fn set(&mut self, key: &str, value: SExp) -> Result {
self.cont.borrow().env().set(key, value)
}
pub(super) fn use_env(&mut self, envt: Rc<Env>) {
self.cont.borrow_mut().set_env(envt);
}
pub(super) fn push_cont(&mut self) {
self.cont = Cont::from(&self.cont).into_rc();
}
pub(super) fn pop_cont(&mut self) {
let new = self.cont.borrow().parent().unwrap_or_default();
self.cont = new;
}
fn eval_args(&mut self, args: SExp) -> Result {
args.into_iter().map(|a| self.eval(a)).collect()
}
pub(super) fn eval_defer(&mut self, body: &SExp) -> Result {
let mut result = Ok(SExp::Atom(Primitive::Undefined));
let mut i = body.iter().peekable();
while let Some(expr) = i.next() {
if i.peek().is_some() {
result = self.eval(expr.clone());
} else {
result = Ok(self.defer(expr.clone()));
}
if result.is_err() {
break;
}
}
result
}
pub fn run(&mut self, expr: &str) -> Result {
self.eval(expr.parse::<SExp>()?)
}
pub fn eval(&mut self, mut expr: SExp) -> Result {
use super::Error::{NotAProcedure, NullList, UndefinedSymbol};
use super::Func::Tail;
use super::Primitive::{Procedure, Symbol, Undefined};
use super::SExp::{Atom, Null, Pair};
self.push_cont();
let res = loop {
expr = match expr {
Null => break Err(NullList),
Atom(Symbol(sym)) => match self.get(&sym) {
None | Some(Atom(Undefined)) => {
break Err(UndefinedSymbol { sym });
}
Some(exp) => exp,
},
Atom(Procedure(Proc {
func: Tail { body, envt },
..
})) => {
self.cont.borrow_mut().set_env(envt);
expr = body.deref().clone();
continue;
}
Atom(_) => break Ok(expr),
Pair { head, tail } => {
match self.eval(*head)? {
Atom(Procedure(p)) => {
let args = if p.defer_eval() {
*tail
} else {
self.eval_args(*tail)?
};
p.apply(args, self)?
}
proc => {
break Err(NotAProcedure {
exp: proc.to_string(),
});
}
}
}
};
match expr {
Atom(Procedure(ref p)) if p.is_tail() => continue,
_ => break Ok(expr),
}
};
self.pop_cont();
res
}
}