diff --git a/src/env/core.rs b/src/env/core.rs index c82586e..d7cf1c2 100644 --- a/src/env/core.rs +++ b/src/env/core.rs @@ -43,6 +43,50 @@ pub(super) fn core() -> HashMap { Ok(val) }), ), + ( + "quasiquote", + Node::Special(|env, args| { + arg_count!(1, args.len()); + + let node = args.into_iter().next().unwrap(); + + // If we have a list as our object, then we need to check for any unquote expressions. + // To do this, we iterate over each value in the list. If we detect that one + // of those values is a list, then we check if the first value in the list is an + // unquote symbol. If it is, then we evaluate the unqote list + match node { + Node::List(list) => { + let inner: Vec = list + .into_iter() + .map(|node| match node { + Node::List(ref list) => match list.first() { + Some(Node::Symbol(symbol)) if symbol == "unquote" => { + eval_node(env, node) + } + Some(_) => Ok(node), + None => Ok(Node::Nil), + }, + _ => Ok(node), + }) + .map(|node| node) + .collect::, _>>()?; + + Ok(Node::List(inner)) + } + + node => Ok(node), + } + }), + ), + ( + "unquote", + Node::Special(|env, args| { + arg_count!(1, args.len()); + + let node = args.into_iter().next().unwrap(); + eval_node(env, node) + }), + ), // Arithmetic operations ( "+", diff --git a/src/evaluator.rs b/src/evaluator.rs index 859bf86..189644c 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -97,9 +97,12 @@ mod test { #[case("(eval (list + 1 1))", "2")] #[case("(apply + (list 1 2 3))", "6")] #[case("'(1 2 3)", "(1 2 3)")] + // Quoting #[case("(quote (1 2 3))", "(1 2 3)")] #[case("'(1 2 (4 5) 6 7)", "(1 2 (4 5) 6 7)")] #[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)")] // Arithmetic #[case("(+ 1 2)", "3")] #[case("(- 5 1)", "4")]