From 02463197c3a6602a8e862b6fcca7f7134c8b76b2 Mon Sep 17 00:00:00 2001 From: Roman Godmaire Date: Sun, 12 May 2024 08:11:12 -0400 Subject: [PATCH] misc: Chesterton's Fence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Everything is a list in lisp for a reason 🙃 --- mute-interpreter/src/env/core.rs | 7 + mute-interpreter/src/error.rs | 2 + mute-interpreter/src/evaluator.rs | 177 ++++++++++-- mute-macros/src/lib.rs | 121 ++------- ...sts__format_node@(define (a 1) (b 2)).snap | 2 +- ...os__tests__format_node@(define (a 1)).snap | 2 +- ...__tests__format_node@(fn* () (+ 1 1)).snap | 2 +- ...ests__format_node@(fn* (a b) (+ a b)).snap | 2 +- ...ros__tests__format_node@(if true 1 2).snap | 2 +- mute-parser/src/lexer.rs | 2 + mute-parser/src/lib.rs | 257 ++---------------- mute-parser/src/node.rs | 153 +++-------- src/main.rs | 2 +- 13 files changed, 245 insertions(+), 486 deletions(-) diff --git a/mute-interpreter/src/env/core.rs b/mute-interpreter/src/env/core.rs index cf1a6e7..11e51ce 100644 --- a/mute-interpreter/src/env/core.rs +++ b/mute-interpreter/src/env/core.rs @@ -54,6 +54,13 @@ macro_rules! ordering { pub(super) fn core() -> HashMap { [ + ( + "dbg", + NativeFunc(|args| { + dbg!(args); + Node::Void + }), + ), // Arithmetic operations ("+", arithmetic!(+)), ("-", arithmetic!(-)), diff --git a/mute-interpreter/src/error.rs b/mute-interpreter/src/error.rs index a3bf81f..3ef3519 100644 --- a/mute-interpreter/src/error.rs +++ b/mute-interpreter/src/error.rs @@ -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, } diff --git a/mute-interpreter/src/evaluator.rs b/mute-interpreter/src/evaluator.rs index a6d9467..d724c87 100644 --- a/mute-interpreter/src/evaluator.rs +++ b/mute-interpreter/src/evaluator.rs @@ -6,7 +6,29 @@ use mute_parser::Node; pub fn eval(env: &Environment, ast: Vec) -> Result> { 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::>(); + + ast = expand_macro(env, parameters.to_owned(), args, body.cloned().collect())? + .into_iter() + .chain(ast) + .collect::>() + .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 { 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 { 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::>())?; 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::>(), + )? { + 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::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::>>()? .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::>>()?; + 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::>>()?, + _ => 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::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 { Ok(expr) } +fn read_parameters(node: Node) -> Result> { + match node { + Node::List(parameters) => parameters + .iter() + .map(|node| match node { + Node::Symbol(name) => Ok(name.clone()), + _ => todo!(), + }) + .collect::>>(), + _ => todo!(), + } +} + +fn expand_macro( + env: &Environment, + parameters: Vec, + args: Vec, + body: Vec, +) -> Result> { + 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::>(); + + 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) diff --git a/mute-macros/src/lib.rs b/mute-macros/src/lib.rs index d28e8e9..018ac70 100644 --- a/mute-macros/src/lib.rs +++ b/mute-macros/src/lib.rs @@ -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) -> 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::*; diff --git a/mute-macros/src/snapshots/mute_macros__tests__format_node@(define (a 1) (b 2)).snap b/mute-macros/src/snapshots/mute_macros__tests__format_node@(define (a 1) (b 2)).snap index b669ef7..dc11a59 100644 --- a/mute-macros/src/snapshots/mute_macros__tests__format_node@(define (a 1) (b 2)).snap +++ b/mute-macros/src/snapshots/mute_macros__tests__format_node@(define (a 1) (b 2)).snap @@ -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)])]) diff --git a/mute-macros/src/snapshots/mute_macros__tests__format_node@(define (a 1)).snap b/mute-macros/src/snapshots/mute_macros__tests__format_node@(define (a 1)).snap index b79338c..af37fa9 100644 --- a/mute-macros/src/snapshots/mute_macros__tests__format_node@(define (a 1)).snap +++ b/mute-macros/src/snapshots/mute_macros__tests__format_node@(define (a 1)).snap @@ -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)])]) diff --git a/mute-macros/src/snapshots/mute_macros__tests__format_node@(fn* () (+ 1 1)).snap b/mute-macros/src/snapshots/mute_macros__tests__format_node@(fn* () (+ 1 1)).snap index 97dc8f5..e79d6a7 100644 --- a/mute-macros/src/snapshots/mute_macros__tests__format_node@(fn* () (+ 1 1)).snap +++ b/mute-macros/src/snapshots/mute_macros__tests__format_node@(fn* () (+ 1 1)).snap @@ -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)])]) diff --git a/mute-macros/src/snapshots/mute_macros__tests__format_node@(fn* (a b) (+ a b)).snap b/mute-macros/src/snapshots/mute_macros__tests__format_node@(fn* (a b) (+ a b)).snap index 68e83b8..df66b6e 100644 --- a/mute-macros/src/snapshots/mute_macros__tests__format_node@(fn* (a b) (+ a b)).snap +++ b/mute-macros/src/snapshots/mute_macros__tests__format_node@(fn* (a b) (+ a b)).snap @@ -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())])]) diff --git a/mute-macros/src/snapshots/mute_macros__tests__format_node@(if true 1 2).snap b/mute-macros/src/snapshots/mute_macros__tests__format_node@(if true 1 2).snap index 1ba629a..7dd5779 100644 --- a/mute-macros/src/snapshots/mute_macros__tests__format_node@(if true 1 2).snap +++ b/mute-macros/src/snapshots/mute_macros__tests__format_node@(if true 1 2).snap @@ -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)]) diff --git a/mute-parser/src/lexer.rs b/mute-parser/src/lexer.rs index 023087c..f1a881d 100644 --- a/mute-parser/src/lexer.rs +++ b/mute-parser/src/lexer.rs @@ -35,6 +35,7 @@ pub enum Token { Nil, // Specials + Macro, Function, Define, Let, @@ -209,6 +210,7 @@ fn read_ident(input: &mut Peekable, first: char) -> Token { "false" => Token::False, "nil" => Token::Nil, "fn*" => Token::Function, + "macro*" => Token::Macro, "define" => Token::Define, "let*" => Token::Let, "eval" => Token::Eval, diff --git a/mute-parser/src/lib.rs b/mute-parser/src/lib.rs index 6f559ae..e2f20d6 100644 --- a/mute-parser/src/lib.rs +++ b/mute-parser/src/lib.rs @@ -30,33 +30,30 @@ fn next_statement(tokens: &mut TokenIter) -> Result> { 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> { 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 { Ok(node) } -fn read_define(tokens: &mut TokenIter) -> Result { - 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 { - 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 { - 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::>>()?; - - 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 { - 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 { - 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 { - 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 { - 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> { 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> { None => Err(Error::UnclosedParenthesis)?, } } + tokens.next(); // Munch closing parenthesis Ok(body) } diff --git a/mute-parser/src/node.rs b/mute-parser/src/node.rs index 57a520b..6b967da 100644 --- a/mute-parser/src/node.rs +++ b/mute-parser/src/node.rs @@ -19,41 +19,20 @@ pub enum Node { Map(HashMap), // Specials - Define { - args: Vec<(String, Node)>, - }, - Let { - args: Vec<(String, Node)>, - body: Vec, - }, - Function { - parameters: Vec, - body: Vec, - }, - Macro { - parameters: Vec, - body: Vec, - }, - If { - cond: Box, - consequence: Box, - alternative: Box, - }, + // TODO: Specials should point to a LinkedList + Define(Vec), + Let(Vec), + Function(Vec), + Macro(Vec), + If(Vec), Quote(Box), Quasiquote(Box), Unquote(Box), - Do { - body: Vec, - }, - Eval { - body: Box, - }, - Apply { - func: Box, - args: Box, - }, + Do(Vec), + Eval(Vec), + Apply(Vec), } 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) -> String { + list.iter() + .map(|n| n.to_string()) + .reduce(|lhs, rhs| format!("{lhs} {rhs}")) + .unwrap_or_default() +} diff --git a/src/main.rs b/src/main.rs index c45ea53..8f29fe2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -79,7 +79,7 @@ fn repl() { Ok(ast) => ast, Err(err) => { println!("error: {}", err); - return; + continue; } }; let res = eval(&env, ast);