mirror of https://github.com/vinc/moros.git
139 lines
5.4 KiB
Rust
139 lines
5.4 KiB
Rust
use super::{Err, Exp, Env};
|
|
use super::env::{env_get, macro_env};
|
|
use super::eval::eval;
|
|
|
|
use crate::{ensure_length_eq, ensure_length_gt, ensure_list, ensure_string, expected};
|
|
|
|
use alloc::format;
|
|
use alloc::rc::Rc;
|
|
use alloc::string::ToString;
|
|
use alloc::vec::Vec;
|
|
use alloc::vec;
|
|
use core::cell::RefCell;
|
|
|
|
pub fn expand_quasiquote(exp: &Exp) -> Result<Exp, Err> {
|
|
match exp {
|
|
Exp::List(list) if list.len() > 0 => {
|
|
match &list[0] {
|
|
Exp::Sym(s) if s == "unquote" => {
|
|
Ok(list[1].clone())
|
|
}
|
|
Exp::List(l) if l.len() == 2 && l[0] == Exp::Sym("unquote-splice".to_string()) => {
|
|
Ok(Exp::List(vec![
|
|
Exp::Sym("concat".to_string()),
|
|
l[1].clone(),
|
|
expand_quasiquote(&Exp::List(list[1..].to_vec()))?
|
|
]))
|
|
}
|
|
_ => {
|
|
Ok(Exp::List(vec![
|
|
Exp::Sym("cons".to_string()),
|
|
expand_quasiquote(&list[0])?,
|
|
expand_quasiquote(&Exp::List(list[1..].to_vec()))?,
|
|
]))
|
|
}
|
|
}
|
|
}
|
|
_ => Ok(Exp::List(vec![Exp::Sym("quote".to_string()), exp.clone()])),
|
|
}
|
|
}
|
|
|
|
pub fn expand_list(list: &[Exp], env: &mut Rc<RefCell<Env>>) -> Result<Exp, Err> {
|
|
let expanded: Result<Vec<Exp>, Err> = list.iter().map(|item| expand(item, env)).collect();
|
|
Ok(Exp::List(expanded?))
|
|
}
|
|
|
|
pub fn expand(exp: &Exp, env: &mut Rc<RefCell<Env>>) -> Result<Exp, Err> {
|
|
if let Exp::List(list) = exp {
|
|
ensure_length_gt!(list, 0);
|
|
match &list[0] {
|
|
Exp::Sym(s) if s == "quote" => {
|
|
ensure_length_eq!(list, 2);
|
|
Ok(exp.clone())
|
|
}
|
|
Exp::Sym(s) if s == "quasiquote" => {
|
|
ensure_length_eq!(list, 2);
|
|
expand_quasiquote(&list[1])
|
|
}
|
|
Exp::Sym(s) if s == "define-function" || s == "define" => {
|
|
let (params, body) = match list.len() {
|
|
3 => {
|
|
ensure_list!(&list[2]);
|
|
(&list[1], &list[2])
|
|
}
|
|
4 => {
|
|
ensure_string!(&list[2]);
|
|
ensure_list!(&list[3]);
|
|
(&list[1], &list[3])
|
|
}
|
|
_ => return expected!("3 or 4 arguments"),
|
|
};
|
|
match params {
|
|
Exp::List(args) => {
|
|
ensure_length_gt!(args, 0);
|
|
let name = args[0].clone();
|
|
let args = Exp::List(args[1..].to_vec());
|
|
let body = expand(body, env)?;
|
|
let mut function = vec![Exp::Sym("function".to_string()), args, body];
|
|
if list.len() == 4 {
|
|
function.insert(2, list[2].clone());
|
|
}
|
|
Ok(Exp::List(vec![
|
|
Exp::Sym("variable".to_string()), name, Exp::List(function)
|
|
]))
|
|
}
|
|
Exp::Sym(_) => expand_list(list, env),
|
|
_ => expected!("first argument to be a symbol or a list")
|
|
}
|
|
}
|
|
Exp::Sym(s) if s == "define-macro" => {
|
|
ensure_length_eq!(list, 3);
|
|
match (&list[1], &list[2]) {
|
|
(Exp::List(args), Exp::List(_)) => {
|
|
ensure_length_gt!(args, 0);
|
|
let name = args[0].clone();
|
|
let args = Exp::List(args[1..].to_vec());
|
|
let body = expand(&list[2], env)?;
|
|
Ok(Exp::List(vec![
|
|
Exp::Sym("variable".to_string()), name, Exp::List(vec![
|
|
Exp::Sym("macro".to_string()), args, body
|
|
])
|
|
]))
|
|
}
|
|
(Exp::Sym(_), _) => expand_list(list, env),
|
|
_ => expected!("first argument to be a symbol or a list")
|
|
}
|
|
}
|
|
Exp::Sym(s) if s == "cond" => {
|
|
ensure_length_gt!(list, 1);
|
|
if let Exp::List(args) = &list[1] {
|
|
ensure_length_eq!(args, 2);
|
|
let test_exp = expand(&args[0], env)?;
|
|
let then_exp = expand(&args[1], env)?;
|
|
let mut res = vec![Exp::Sym("if".to_string()), test_exp, then_exp];
|
|
if list.len() > 2 {
|
|
let mut acc = vec![Exp::Sym("cond".to_string())];
|
|
acc.extend_from_slice(&list[2..]);
|
|
res.push(expand(&Exp::List(acc), env)?);
|
|
}
|
|
Ok(Exp::List(res))
|
|
} else {
|
|
expected!("lists of predicate and expression")
|
|
}
|
|
}
|
|
Exp::Sym(s) => {
|
|
if let Ok(Exp::Macro(m)) = env_get(s, env) {
|
|
let mut m_env = macro_env(&m.params, &list[1..], env)?;
|
|
let m_exp = m.body;
|
|
expand(&eval(&m_exp, &mut m_env)?, env)
|
|
} else {
|
|
expand_list(list, env)
|
|
}
|
|
}
|
|
_ => expand_list(list, env),
|
|
}
|
|
} else {
|
|
Ok(exp.clone())
|
|
}
|
|
}
|