diff --git a/mute-interpreter/src/env/mod.rs b/mute-interpreter/src/env/mod.rs index 74063d9..7b2883d 100644 --- a/mute-interpreter/src/env/mod.rs +++ b/mute-interpreter/src/env/mod.rs @@ -34,6 +34,14 @@ pub struct RawEnvironment { } impl Environment { + pub fn get_node(&self, ident: &str) -> Option { + match self.get(ident) { + Some(Value::NativeFunc(_)) => Some(Node::Symbol(ident.to_string())), + Some(Value::Node(val)) => Some(val.clone()), + None => None, + } + } + pub fn get(&self, ident: &str) -> Option { if let Some(val) = self.0.current.borrow().get(ident) { return Some(val.clone()); diff --git a/mute-interpreter/src/env/standard.rs b/mute-interpreter/src/env/standard.rs index d54b335..afa7368 100644 --- a/mute-interpreter/src/env/standard.rs +++ b/mute-interpreter/src/env/standard.rs @@ -6,12 +6,20 @@ use mute_parser::Node; use super::Value; pub(super) fn standard() -> HashMap { - [( - "test", - inline! { - (fn* () (println "Hello, world!")) - }, - )] + [ + ( + "defmacro", + inline! { + (macro* (name args body) ~(define (,name (macro* ,args ,body)))) + }, + ), + ( + "defun", + inline! { + (macro* (name args body) ~(define (,name (fn* ,args ,body))) ) + }, + ), + ] .into_iter() .map(|(k, v)| (k.to_string(), Value::Node(v))) .collect() diff --git a/mute-interpreter/src/evaluator.rs b/mute-interpreter/src/evaluator.rs index d724c87..b599b4d 100644 --- a/mute-interpreter/src/evaluator.rs +++ b/mute-interpreter/src/evaluator.rs @@ -14,7 +14,15 @@ pub fn eval(env: &Environment, ast: Vec) -> Result> { }; if let Node::List(list) = &node { - if let Some(Node::Macro(body)) = list.first() { + let first = match list.first() { + Some(Node::Symbol(ident)) => match env.get_node(ident) { + m @ Some(Node::Macro(_)) => m, + _ => None, + }, + node => node.cloned(), + }; + + if let Some(Node::Macro(body)) = first { let mut body = body.iter(); let parameters = body.next().ok_or_else(|| todo!())?; let parameters = read_parameters(parameters.clone())?; @@ -89,7 +97,7 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result { args.collect(), body.cloned().collect::>(), )? { - nodes if nodes.len() == 1 => nodes[0].to_owned(), + nodes if nodes.len() == 1 => eval_node(env, nodes[0].to_owned())?, _ => Err(Error::MacroExpansion)?, } } @@ -183,14 +191,26 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result { Node::Quote(node) => *node, Node::Quasiquote(node) => { fn unquote(env: &Environment, node: Node) -> Result { - match node { - Node::List(list) => { - let list = list + macro_rules! unquote { + ($variant:ident, $list:ident) => {{ + let list = $list .into_iter() .map(|node| unquote(env, node)) .collect::>>()?; - Ok(Node::List(list)) - } + Ok(Node::$variant(list)) + }}; + } + match node { + Node::List(list) => unquote!(List, list), + Node::Define(list) => unquote!(Define, list), + Node::Let(list) => unquote!(Let, list), + Node::Function(list) => unquote!(Function, list), + Node::Macro(list) => unquote!(Macro, list), + Node::If(list) => unquote!(If, list), + Node::Do(list) => unquote!(Do, list), + Node::Eval(list) => unquote!(Do, list), + Node::Apply(list) => unquote!(Apply, list), + Node::Unquote(_) => eval_node(env, node), node => Ok(node), } @@ -221,15 +241,10 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result { eval_node(env, Node::List(nodes))? } - Node::Symbol(sym) => match env - .get(&sym) + Node::Symbol(sym) => env + .get_node(&sym) .ok_or_else(|| Error::NotInEnv(sym.clone()))? - .to_owned() - { - crate::env::Value::Node(node) => node, - // HACK: This feels so wrong - crate::env::Value::NativeFunc(_) => Node::Symbol(sym), - }, + .to_owned(), Node::Keyword(_) | Node::Int(_) diff --git a/mute-parser/src/lexer.rs b/mute-parser/src/lexer.rs index f1a881d..74e5fc9 100644 --- a/mute-parser/src/lexer.rs +++ b/mute-parser/src/lexer.rs @@ -94,6 +94,7 @@ fn next_token(input: &mut Peekable) -> Result, Error> { '\'' => Token::Quote, '`' => Token::Quasiquote, + '~' => Token::Quasiquote, ',' => Token::Unquote, '+' => Token::Plus, @@ -215,9 +216,6 @@ fn read_ident(input: &mut Peekable, first: char) -> Token { "let*" => Token::Let, "eval" => Token::Eval, "apply" => Token::Apply, - "quote" => Token::Quote, - "quasiquote" => Token::Quasiquote, - "unquote" => Token::Unquote, "if" => Token::If, "do" => Token::Do, ident => Token::Ident(ident.to_owned()), diff --git a/mute-parser/src/lib.rs b/mute-parser/src/lib.rs index e2f20d6..c008bb3 100644 --- a/mute-parser/src/lib.rs +++ b/mute-parser/src/lib.rs @@ -30,15 +30,6 @@ 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 => Node::Function(read_body(tokens)?), @@ -50,10 +41,6 @@ fn next_statement(tokens: &mut TokenIter) -> Result> { 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)?, }, @@ -155,11 +142,6 @@ fn read_body(tokens: &mut TokenIter) -> Result> { tokens.next(); // Munch special while tokens.peek() != Some(&Token::RightParen) { - if let Some(node) = next_statement(tokens)? { - body.push(node); - continue; - } - match next_statement(tokens)? { Some(node) => body.push(node), None => Err(Error::UnclosedParenthesis)?, diff --git a/mute-parser/src/node.rs b/mute-parser/src/node.rs index 6b967da..9efc1cb 100644 --- a/mute-parser/src/node.rs +++ b/mute-parser/src/node.rs @@ -100,7 +100,7 @@ impl std::fmt::Display for Node { .unwrap_or_default() ), - Node::Define(body) => write!(f, "(define! {})", reduce_list(body)), + 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)),