misc: Chesterton's Fence

Everything is a list in lisp for a reason 🙃
This commit is contained in:
Roman Godmaire 2024-05-12 08:11:12 -04:00
parent 047db2b188
commit 02463197c3
13 changed files with 245 additions and 486 deletions

View file

@ -54,6 +54,13 @@ macro_rules! ordering {
pub(super) fn core() -> HashMap<String, Value> {
[
(
"dbg",
NativeFunc(|args| {
dbg!(args);
Node::Void
}),
),
// Arithmetic operations
("+", arithmetic!(+)),
("-", arithmetic!(-)),

View file

@ -26,6 +26,8 @@ pub enum Error {
#[error("system error {0}")]
SystemError(String),
#[error("INTERNAL: Incorrect macro expansion, please file a bug report")]
MacroExpansion,
#[error("please file a bug report")]
Unreachable,
}

View file

@ -6,7 +6,29 @@ use mute_parser::Node;
pub fn eval(env: &Environment, ast: Vec<Node>) -> Result<Vec<Node>> {
let mut exprs = Vec::new();
for node in ast {
let mut ast = ast.into_iter();
loop {
let node = match ast.next() {
Some(node) => node,
None => break,
};
if let Node::List(list) = &node {
if let Some(Node::Macro(body)) = list.first() {
let mut body = body.iter();
let parameters = body.next().ok_or_else(|| todo!())?;
let parameters = read_parameters(parameters.clone())?;
let args = list.clone().into_iter().skip(1).collect::<Vec<Node>>();
ast = expand_macro(env, parameters.to_owned(), args, body.cloned().collect())?
.into_iter()
.chain(ast)
.collect::<Vec<Node>>()
.into_iter();
continue;
}
}
let res = eval_node(env, node)?;
if let Node::Void = res {
continue;
@ -31,7 +53,11 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
let operator = eval_node(env, list.next().ok_or(Error::InvalidOperator)?)?;
match operator.borrow() {
Node::Function { parameters, body } => {
Node::Function(body) => {
let mut body = body.iter();
let parameters = body.next().ok_or_else(|| todo!())?;
let parameters = read_parameters(parameters.clone())?;
let args = list;
if args.len() != parameters.len() {
Err(Error::MismatchedArgCount(parameters.len(), args.len()))?
@ -44,13 +70,30 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
let records = parameters.iter().map(|k| k.to_owned()).zip(args).collect();
let env = env.wrap(records);
let res = eval(&env, (*body).clone())?;
let res = eval(&env, body.cloned().collect::<Vec<Node>>())?;
match res.last() {
Some(node) => node.to_owned(),
None => Node::Void,
}
}
Node::Macro(body) => {
let mut body = body.iter();
let parameters = body.next().ok_or_else(|| todo!())?;
let parameters = read_parameters(parameters.clone())?;
let args = list;
match expand_macro(
env,
parameters.clone(),
args.collect(),
body.cloned().collect::<Vec<Node>>(),
)? {
nodes if nodes.len() == 1 => nodes[0].to_owned(),
_ => Err(Error::MacroExpansion)?,
}
}
// HACK: This feels sooooooo wrong but it works
// Native Functions /should/ be their own type, but they're not.
Node::Symbol(sym) => {
@ -71,35 +114,68 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
}
}
Node::Define { args } => {
args.into_iter()
.map(|(k, v)| Ok((k.to_owned(), eval_node(env, v)?)))
Node::Define(body) => {
body.into_iter()
.map(|n| match n {
Node::List(list) if list.len() == 2 => Ok((list[0].clone(), list[1].clone())),
Node::List(list) => Err(Error::MismatchedArgCount(2, list.len()))?,
_ => todo!(),
})
.map(|n| match n {
Ok((Node::Symbol(k), v)) => Ok((k.to_owned(), eval_node(env, v)?)),
Ok(_) => todo!(),
Err(e) => Err(e),
})
.collect::<Result<Vec<(String, Node)>>>()?
.into_iter()
.for_each(|(k, v)| env.set(k, v));
Node::Void
}
Node::Let { args, body } => {
let args = args
.into_iter()
.map(|(k, v)| Ok((k.to_owned(), eval_node(env, v)?)))
.collect::<Result<Vec<(String, Node)>>>()?;
Node::Let(body) => {
let mut body = body.into_iter();
let args = match body.next().ok_or_else(|| todo!())? {
Node::List(list) => list
.into_iter()
.map(|n| match n {
Node::List(list) if list.len() == 2 => {
Ok((list[0].clone(), list[1].clone()))
}
Node::List(list) => Err(Error::MismatchedArgCount(2, list.len()))?,
_ => todo!(),
})
.map(|n| match n {
Ok((Node::Symbol(k), v)) => Ok((k.to_owned(), eval_node(env, v)?)),
Ok(_) => todo!(),
Err(e) => Err(e),
})
.collect::<Result<Vec<(String, Node)>>>()?,
_ => Err(Error::MismatchedArgCount(1, 1))?,
};
let body = body.collect();
let env = env.wrap(args);
eval(&env, body)?.last().unwrap().to_owned()
}
Node::If {
cond,
consequence,
alternative,
} => {
let cond = eval_node(env, *cond)?;
Node::If(body) => {
if body.len() != 2 && body.len() != 3 {
Err(Error::MismatchedArgCount(3, body.len()))?
}
let mut body = body.iter();
let cond = body.next().expect("arg count verified above").clone();
let consequence = body.next().expect("arg count verified above").clone();
let alternative = match body.next() {
Some(node) => node.clone(),
None => Node::Nil,
};
let cond = eval_node(env, cond)?;
match cond {
Node::Boolean(true) => eval_node(env, *consequence)?,
Node::Boolean(false) => eval_node(env, *alternative)?,
Node::Boolean(true) => eval_node(env, consequence)?,
Node::Boolean(false) => eval_node(env, alternative)?,
_ => Err(Error::ExpectedBoolean)?,
}
}
@ -124,16 +200,25 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
}
Node::Unquote(node) => eval_node(env, *node)?,
Node::Do { body } => eval(env, body)?.last().unwrap().to_owned(),
Node::Eval { body } => eval_node(env, eval_node(env, *body)?)?,
Node::Apply { func, args } => {
let mut list = vec![*func];
match eval_node(env, *args)? {
Node::List(args) => list.extend(args),
_ => Err(Error::ExpectedList)?,
}
Node::Do(body) => eval(env, body)?.last().unwrap().to_owned(),
// FIXME: check for empty body
Node::Eval(body) => eval_node(env, eval_node(env, body[0].clone())?)?,
Node::Apply(body) => {
let mut body = body.into_iter();
let operator = eval_node(env, body.next().ok_or(Error::InvalidOperator)?)?;
eval_node(env, Node::List(list))?
let args = match body.next() {
Some(node) => match eval_node(env, node)? {
Node::List(list) => list,
_ => todo!(),
},
None => return Err(Error::MismatchedArgCount(2, 1)),
};
let mut nodes = vec![operator];
nodes.extend(args);
eval_node(env, Node::List(nodes))?
}
Node::Symbol(sym) => match env
@ -163,6 +248,39 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
Ok(expr)
}
fn read_parameters(node: Node) -> Result<Vec<String>> {
match node {
Node::List(parameters) => parameters
.iter()
.map(|node| match node {
Node::Symbol(name) => Ok(name.clone()),
_ => todo!(),
})
.collect::<Result<Vec<String>>>(),
_ => todo!(),
}
}
fn expand_macro(
env: &Environment,
parameters: Vec<String>,
args: Vec<Node>,
body: Vec<Node>,
) -> Result<Vec<Node>> {
if args.len() != parameters.len() {
Err(Error::MismatchedArgCount(parameters.len(), args.len()))?
}
let args = parameters
.into_iter()
.map(|param| param.to_owned())
.zip(args)
.collect::<Vec<(String, Node)>>();
let env = env.wrap(args);
eval(&env, body)
}
#[cfg(test)]
mod test {
use mute_parser::parse_str;
@ -194,6 +312,8 @@ mod test {
#[case("(quote (1 2 (4 5) 6 7))", "(1 2 (4 5) 6 7)")]
#[case("(quasiquote (1 2 (+ 3 4) 5 6))", "(1 2 (+ 3 4) 5 6)")]
#[case("(quasiquote (1 2 (unquote(+ 3 4)) 5 6))", "(1 2 7 5 6)")]
// Macros
#[case("((macro* (var) `(str ,var)) 2)", "2")]
// Arithmetic
#[case("(+ 1 2)", "3")]
#[case("(- 5 1)", "4")]
@ -289,6 +409,7 @@ mod test {
#[case("(str (list 1 2 3))", "(1 2 3)")]
fn test_evaluator(#[case] input: &str, #[case] expected: &str) {
dbg!(input);
let env = Environment::default();
let ast = parse_str(input).unwrap();
let res = crate::eval(&env, ast)

View file

@ -18,15 +18,7 @@ pub fn inline(input: TokenStream) -> TokenStream {
fn format_node(node: Node) -> String {
match node {
Node::List(v) => {
let vec = v
.into_iter()
.map(format_node)
.reduce(|lhs, rhs| format!("{lhs}, {rhs}"))
.unwrap_or_default();
format!("Node::List(vec![{vec}])")
}
Node::List(v) => format!("Node::List({})", reduce_list(v)),
Node::Symbol(s) => format!("Node::Symbol(\"{s}\".to_string())"),
Node::Keyword(k) => format!("Node::Keyword(\"{k}\".to_string())"),
@ -39,103 +31,36 @@ fn format_node(node: Node) -> String {
Node::Error(e) => format!("Node::Error(\"{e}\".to_string())"),
Node::Vector(v) => {
let vec = v
.into_iter()
.map(format_node)
.reduce(|lhs, rhs| format!("{lhs}, {rhs}"))
.unwrap_or_default();
format!("Node::Vector(vec![{vec}])")
}
Node::Map(v) => {
let vec = v
.into_iter()
.map(|(k, v)| (k, format_node(v)))
.map(|(k, v)| format!("({k}, {v})"))
.reduce(|lhs, rhs| format!("{lhs}, {rhs}"))
.unwrap_or_default();
format!("Node::Hashmap(vec![{vec}].into())")
}
Node::Define { args } => {
let args = args
.into_iter()
.map(|(k, v)| format!("(\"{}\".to_string(), {})", k, format_node(v)))
.reduce(|lhs, rhs| format!("{lhs}, {rhs}"))
.unwrap_or_default();
format!("Node::Define(vec![{args}])")
}
Node::Let { args, body } => {
let args = args
.into_iter()
.map(|(k, v)| (k, format_node(v)))
.fold(String::new(), |lhs, (k, v)| {
format!("{lhs}, ({k}.to_string(), {v})")
});
let body = body
.into_iter()
.map(format_node)
.reduce(|lhs, rhs| format!("{lhs}, {rhs}"))
.unwrap_or_default();
format!("Node::Let(vec![{}], vec![{}]", args, body)
}
Node::Function { parameters, body } => {
let parameters = parameters
.into_iter()
.map(|param| format!("\"{}\".to_string()", param))
.reduce(|lhs, rhs| format!("{lhs}, {rhs}"))
.unwrap_or_default();
let body = body
.into_iter()
.map(format_node)
.reduce(|lhs, rhs| format!("{lhs}, {rhs}"))
.unwrap_or_default();
format!(
"Node::Function {{ parameters: vec![{}], body: vec![{}] }}",
parameters, body
)
}
Node::Macro { .. } => todo!(),
Node::If {
cond,
consequence,
alternative,
} => format!(
"Node::If(Box::new({}), Box::new({}), Box::new({}))",
format_node(*cond),
format_node(*consequence),
format_node(*alternative)
),
Node::Vector(_) => todo!(),
Node::Map(_) => todo!(),
// Quoting
Node::Quote(node) => format!("Node::Quote(Box::new({}))", format_node(*node)),
Node::Quasiquote(node) => format!("Node::Quasiquote(Box::new({}))", format_node(*node)),
Node::Unquote(node) => format!("Node::Unquote(Box::new({}))", format_node(*node)),
Node::Do { body } => {
let vec = body
.into_iter()
.map(format_node)
.reduce(|lhs, rhs| format!("{lhs}, {rhs}"))
.unwrap_or_default();
format!("Node::Do(vec![{vec}])")
}
Node::Eval { body } => format!("Node::Eval(Box::new({}))", format_node(*body)),
Node::Apply { func, args } => format!(
"Node::Apply(Box::new({}), Box::new({}))",
format_node(*func),
format_node(*args)
),
// Specials
Node::Define(body) => format!("Node::Define({})", reduce_list(body)),
Node::Let(body) => format!("Node::Let({})", reduce_list(body)),
Node::Function(body) => format!("Node::Function({})", reduce_list(body)),
Node::Macro(body) => format!("Node::Macro({})", reduce_list(body)),
Node::If(body) => format!("Node::If({})", reduce_list(body)),
Node::Do(body) => format!("Node::Do({})", reduce_list(body)),
Node::Eval(body) => format!("Node::Eval({})", reduce_list(body)),
Node::Apply(body) => format!("Node::Apply({})", reduce_list(body),),
}
}
fn reduce_list(node: Vec<Node>) -> String {
let vec = node
.into_iter()
.map(format_node)
.reduce(|lhs, rhs| format!("{lhs}, {rhs}"))
.unwrap_or_default();
format!("vec![{vec}]")
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -2,4 +2,4 @@
source: mute-macros/src/lib.rs
expression: res
---
Node::Define(vec![("a".to_string(), Node::Int(1)), ("b".to_string(), Node::Int(2))])
Node::Define(vec![Node::List(vec![Node::Symbol("a".to_string()), Node::Int(1)]), Node::List(vec![Node::Symbol("b".to_string()), Node::Int(2)])])

View file

@ -2,4 +2,4 @@
source: mute-macros/src/lib.rs
expression: res
---
Node::Define(vec![("a".to_string(), Node::Int(1))])
Node::Define(vec![Node::List(vec![Node::Symbol("a".to_string()), Node::Int(1)])])

View file

@ -2,4 +2,4 @@
source: mute-macros/src/lib.rs
expression: res
---
Node::Function { parameters: vec![], body: vec![Node::List(vec![Node::Symbol("+".to_string()), Node::Int(1), Node::Int(1)])] }
Node::Function(vec![Node::List(vec![]), Node::List(vec![Node::Symbol("+".to_string()), Node::Int(1), Node::Int(1)])])

View file

@ -2,4 +2,4 @@
source: mute-macros/src/lib.rs
expression: res
---
Node::Function { parameters: vec!["a".to_string(), "b".to_string()], body: vec![Node::List(vec![Node::Symbol("+".to_string()), Node::Symbol("a".to_string()), Node::Symbol("b".to_string())])] }
Node::Function(vec![Node::List(vec![Node::Symbol("a".to_string()), Node::Symbol("b".to_string())]), Node::List(vec![Node::Symbol("+".to_string()), Node::Symbol("a".to_string()), Node::Symbol("b".to_string())])])

View file

@ -2,4 +2,4 @@
source: mute-macros/src/lib.rs
expression: res
---
Node::If(Box::new(Node::Bool(true)), Box::new(Node::Int(1)), Box::new(Node::Int(2)))
Node::If(vec![Node::Bool(true), Node::Int(1), Node::Int(2)])

View file

@ -35,6 +35,7 @@ pub enum Token {
Nil,
// Specials
Macro,
Function,
Define,
Let,
@ -209,6 +210,7 @@ fn read_ident(input: &mut Peekable<Chars>, first: char) -> Token {
"false" => Token::False,
"nil" => Token::Nil,
"fn*" => Token::Function,
"macro*" => Token::Macro,
"define" => Token::Define,
"let*" => Token::Let,
"eval" => Token::Eval,

View file

@ -30,33 +30,30 @@ fn next_statement(tokens: &mut TokenIter) -> Result<Option<Node>> {
None => return Ok(None),
};
macro_rules! read_quote_operator {
($type:expr) => {{
tokens.next(); // Munch opened
let quote = read_quote(tokens, $type)?;
tokens.next(); // Munch closed
quote
}};
}
let node = match tok {
Token::LeftParen => match tokens.peek().ok_or(Error::UnclosedParenthesis)? {
Token::Function => read_function(tokens)?,
Token::Define => read_define(tokens)?,
Token::Let => read_let(tokens)?,
Token::Eval => read_eval(tokens)?,
Token::Apply => read_apply(tokens)?,
Token::If => read_if(tokens)?,
Token::Do => read_do(tokens)?,
Token::Quote => {
tokens.next(); // Munch (
let quote = read_quote(tokens, "quote")?;
tokens.next(); // Munch )
quote
}
Token::Quasiquote => {
tokens.next(); // Munch (
let quote = read_quote(tokens, "quasiquote")?;
tokens.next(); // Munch )
quote
}
Token::Unquote => {
tokens.next(); // Munch (
let quote = read_quote(tokens, "unquote")?;
tokens.next(); // Munch )
quote
}
Token::Function => Node::Function(read_body(tokens)?),
Token::Macro => Node::Macro(read_body(tokens)?),
Token::Define => Node::Define(read_body(tokens)?),
Token::Let => Node::Let(read_body(tokens)?),
Token::Eval => Node::Eval(read_body(tokens)?),
Token::Apply => Node::Apply(read_body(tokens)?),
Token::If => Node::If(read_body(tokens)?),
Token::Do => Node::Do(read_body(tokens)?),
Token::Quote => read_quote_operator!("quote"),
Token::Quasiquote => read_quote_operator!("quasiquote"),
Token::Unquote => read_quote_operator!("unquote"),
_ => read_list(tokens, Token::RightParen)?,
},
@ -92,6 +89,7 @@ fn next_statement(tokens: &mut TokenIter) -> Result<Option<Node>> {
Token::Unquote => read_quote(tokens, "unquote")?,
Token::Function
| Token::Macro
| Token::Define
| Token::Let
| Token::Eval
@ -152,216 +150,10 @@ fn read_quote(tokens: &mut TokenIter, quote_type: &str) -> Result<Node> {
Ok(node)
}
fn read_define(tokens: &mut TokenIter) -> Result<Node> {
tokens.next(); // Munch special
let mut args = Vec::new();
if tokens.peek() == Some(&Token::RightParen) {
return Err(Error::EmptyDefine);
}
while tokens.peek() != Some(&Token::RightParen) {
let values = match next_statement(tokens)? {
Some(Node::List(list)) => list,
Some(node) => Err(Error::ExpectedList(node.get_type()))?,
None => Err(Error::UnexpectedEof)?,
};
if values.len() != 2 {
return Err(Error::MismatchedValueCount(2, values.len()));
}
let mut values = values.into_iter();
let name = match values.next().unwrap() {
Node::Symbol(name) => name,
val => Err(Error::ExpectedSymbol(val.get_type()))?,
};
let value = values.next().unwrap();
args.push((name.to_owned(), value.to_owned()))
}
tokens.next(); // Munch closer
Ok(Node::Define { args })
}
fn read_let(tokens: &mut TokenIter) -> Result<Node> {
tokens.next(); // Munch special
let raw_args = match next_statement(tokens)? {
Some(Node::List(list)) => list,
Some(node) => Err(Error::ExpectedList(node.get_type()))?,
None => Err(Error::UnexpectedEof)?,
};
let mut args = Vec::new();
for node in raw_args.iter() {
match node {
Node::List(list) => {
if list.len() != 2 {
return Err(Error::MismatchedValueCount(2, list.len()));
}
let mut list = list.iter();
let name = match list.next().unwrap() {
Node::Symbol(name) => name,
val => Err(Error::ExpectedSymbol(val.get_type()))?,
};
let value = list.next().unwrap();
args.push((name.to_owned(), value.to_owned()))
}
_ => return Err(Error::ExpectedList(node.get_type()))?,
}
}
let body = read_body(tokens)?;
tokens.next(); // Munch closer
Ok(Node::Let { args, body })
}
fn read_function(tokens: &mut TokenIter) -> Result<Node> {
tokens.next(); // Munch special
let parameters = match next_statement(tokens)? {
Some(Node::List(args)) => args,
Some(Node::Nil) => vec![],
Some(node) => Err(Error::ExpectedList(node.get_type()))?,
None => Err(Error::EmptyFunctionArgs)?,
};
// Ensure all parameters are symbols then extract their names
let parameters = parameters
.into_iter()
.map(|node| match node {
Node::Symbol(name) => Ok(name),
_ => Err(Error::ExpectedSymbol(node.get_type()))?,
})
.collect::<Result<Vec<_>>>()?;
if tokens.peek() == Some(&Token::RightParen) {
return Err(Error::EmptyFunctionBody);
}
let body = read_body(tokens)?;
tokens.next(); // Munch closer
Ok(Node::Function { parameters, body })
}
fn read_eval(tokens: &mut TokenIter) -> Result<Node> {
tokens.next(); // Munch special
let node = match next_statement(tokens)? {
Some(node) => node,
None => Err(Error::UnexpectedEof)?,
};
if tokens.peek() != Some(&Token::RightParen) {
// FIXME: This should not say expected is 0
return Err(Error::MismatchedValueCount(1, 0));
}
tokens.next(); // Munch closer
Ok(Node::Eval {
body: Box::new(node),
})
}
fn read_apply(tokens: &mut TokenIter) -> Result<Node> {
tokens.next(); // Munch special
if tokens.peek() == Some(&Token::RightParen) {
return Err(Error::EmptyApplyOperator);
}
let func = match next_statement(tokens)? {
Some(node) => node,
None => Err(Error::UnexpectedEof)?,
};
if tokens.peek() == Some(&Token::RightParen) {
return Err(Error::EmptyApplyBody);
}
let args = match next_statement(tokens)? {
Some(node) => node,
None => Err(Error::UnexpectedEof)?,
};
tokens.next(); // Munch closer
Ok(Node::Apply {
func: Box::new(func),
args: Box::new(args),
})
}
fn read_if(tokens: &mut TokenIter) -> Result<Node> {
tokens.next(); // Munch special
if tokens.peek() == Some(&Token::RightParen) {
return Err(Error::EmptyIfCondition);
}
let cond = match next_statement(tokens)? {
Some(node) => node,
None => Err(Error::UnexpectedEof)?,
};
if tokens.peek() == Some(&Token::RightParen) {
return Err(Error::EmptyIfConsequence);
}
let consequence = match next_statement(tokens)? {
Some(node) => node,
None => Err(Error::UnexpectedEof)?,
};
let alternative = match tokens.peek() {
Some(&Token::RightParen) => Node::Nil,
Some(_) => match next_statement(tokens)? {
Some(node) => node,
None => Err(Error::UnexpectedEof)?,
},
None => Err(Error::UnexpectedEof)?,
};
tokens.next(); // Munch closer
Ok(Node::If {
cond: Box::new(cond),
consequence: Box::new(consequence),
alternative: Box::new(alternative),
})
}
fn read_do(tokens: &mut TokenIter) -> Result<Node> {
tokens.next(); // Munch special
if tokens.peek() == Some(&Token::RightParen) {
return Err(Error::EmptyDo);
}
let body = read_body(tokens)?;
tokens.next(); // Munch closer
Ok(Node::Do { body })
}
fn read_body(tokens: &mut TokenIter) -> Result<Vec<Node>> {
let mut body = Vec::new();
tokens.next(); // Munch special
while tokens.peek() != Some(&Token::RightParen) {
if let Some(node) = next_statement(tokens)? {
body.push(node);
@ -373,6 +165,7 @@ fn read_body(tokens: &mut TokenIter) -> Result<Vec<Node>> {
None => Err(Error::UnclosedParenthesis)?,
}
}
tokens.next(); // Munch closing parenthesis
Ok(body)
}

View file

@ -19,41 +19,20 @@ pub enum Node {
Map(HashMap<String, Node>),
// Specials
Define {
args: Vec<(String, Node)>,
},
Let {
args: Vec<(String, Node)>,
body: Vec<Node>,
},
Function {
parameters: Vec<String>,
body: Vec<Node>,
},
Macro {
parameters: Vec<String>,
body: Vec<Node>,
},
If {
cond: Box<Node>,
consequence: Box<Node>,
alternative: Box<Node>,
},
// TODO: Specials should point to a LinkedList
Define(Vec<Node>),
Let(Vec<Node>),
Function(Vec<Node>),
Macro(Vec<Node>),
If(Vec<Node>),
Quote(Box<Node>),
Quasiquote(Box<Node>),
Unquote(Box<Node>),
Do {
body: Vec<Node>,
},
Eval {
body: Box<Node>,
},
Apply {
func: Box<Node>,
args: Box<Node>,
},
Do(Vec<Node>),
Eval(Vec<Node>),
Apply(Vec<Node>),
}
impl Node {
@ -111,106 +90,36 @@ impl std::fmt::Display for Node {
Node::Error(val) => write!(f, "error: {}", val),
Node::Vector(vec) => {
let s = vec
.iter()
.map(|elem| elem.to_string())
.reduce(|lhs, rhs| format!("{lhs} {rhs}"))
.unwrap_or_default();
write!(f, "[{s}]")
}
Node::Map(map) => {
let res = map
.iter()
Node::Vector(body) => write!(f, "[{}]", reduce_list(body)),
Node::Map(body) => write!(
f,
"{{{}}}",
body.iter()
.map(|(k, v)| format!("{k}: {v}"))
.reduce(|lhs, rhs| format!("{lhs}, {rhs}"))
.unwrap_or_default();
write!(f, "{{{res}}}")
}
Node::Define { args } => {
let res = args
.iter()
.map(|(k, v)| format!("({k} {v})"))
.reduce(|lhs, rhs| format!("{lhs} {rhs}"))
.expect("parser does not allow empty define statements");
.unwrap_or_default()
),
write!(f, "(define {res})")
}
Node::Let { args, body } => {
let args = args
.iter()
.map(|(k, v)| format!("({k} {v})"))
.reduce(|lhs, rhs| format!("{lhs} {rhs}"))
.expect("parser does not allow empty let statements");
let body = body
.iter()
.map(|node| node.to_string())
.reduce(|lhs, rhs| format!("{lhs} {rhs}"))
.expect("parser does not allow empty let bodies");
write!(f, "(let ({args}) {body})")
}
Node::Macro {
parameters: args,
body,
} => {
let args = args
.iter()
.map(|node| node.to_string())
.reduce(|lhs, rhs| format!("{lhs} {rhs}"))
.unwrap_or_default();
let body = body
.iter()
.map(|node| node.to_string())
.reduce(|lhs, rhs| format!("{lhs} {rhs}"))
.expect("parser does not allow empty function bodies");
write!(f, "(fn ({args}) {body})")
}
Node::Function {
parameters: args,
body,
} => {
let args = args
.iter()
.map(|node| node.to_string())
.reduce(|lhs, rhs| format!("{lhs} {rhs}"))
.unwrap_or_default();
let body = body
.iter()
.map(|node| node.to_string())
.reduce(|lhs, rhs| format!("{lhs} {rhs}"))
.expect("parser does not allow empty function bodies");
write!(f, "(defmacro ({args}) {body})")
}
Node::If {
cond,
consequence,
alternative,
} => write!(f, "(if {cond} {consequence} {alternative})"),
Node::Define(body) => write!(f, "(define! {})", reduce_list(body)),
Node::Let(body) => write!(f, "(let* {})", reduce_list(body)),
Node::Macro(body) => write!(f, "(macro* {})", reduce_list(body)),
Node::Function(body) => write!(f, "(fn* {})", reduce_list(body)),
Node::If(body) => write!(f, "(if {})", reduce_list(body)),
Node::Quote(node) => write!(f, "'{node}"),
Node::Quasiquote(node) => write!(f, "`{node}"),
Node::Unquote(node) => write!(f, ",{node}"),
Node::Do { body } => {
let body = body
.iter()
.map(|node| node.to_string())
.reduce(|lhs, rhs| format!("{lhs} {rhs}"))
.expect("parser does not allow empty do statements");
write!(f, "(do {body})")
}
Node::Eval { body } => write!(f, "(eval {body})"),
Node::Apply { func, args } => write!(f, "(apply {func} {args})"),
Node::Do(body) => write!(f, "(do {})", reduce_list(body)),
Node::Eval(body) => write!(f, "(eval {})", reduce_list(body)),
Node::Apply(body) => write!(f, "(apply {})", reduce_list(body)),
}
}
}
fn reduce_list(list: &Vec<Node>) -> String {
list.iter()
.map(|n| n.to_string())
.reduce(|lhs, rhs| format!("{lhs} {rhs}"))
.unwrap_or_default()
}

View file

@ -79,7 +79,7 @@ fn repl() {
Ok(ast) => ast,
Err(err) => {
println!("error: {}", err);
return;
continue;
}
};
let res = eval(&env, ast);