misc: Chesterton's Fence
Everything is a list in lisp for a reason 🙃
This commit is contained in:
parent
047db2b188
commit
02463197c3
13 changed files with 245 additions and 486 deletions
7
mute-interpreter/src/env/core.rs
vendored
7
mute-interpreter/src/env/core.rs
vendored
|
@ -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!(-)),
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
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(|(k, v)| Ok((k.to_owned(), eval_node(env, v)?)))
|
||||
.collect::<Result<Vec<(String, Node)>>>()?;
|
||||
.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)
|
||||
|
|
|
@ -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,101 +31,34 @@ 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
|
||||
// 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!("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)
|
||||
),
|
||||
}
|
||||
format!("vec![{vec}]")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -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)])])
|
||||
|
|
|
@ -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)])])
|
||||
|
|
|
@ -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)])])
|
||||
|
|
|
@ -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())])])
|
||||
|
|
|
@ -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)])
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ fn repl() {
|
|||
Ok(ast) => ast,
|
||||
Err(err) => {
|
||||
println!("error: {}", err);
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let res = eval(&env, ast);
|
||||
|
|
Loading…
Reference in a new issue