feat: quasiquote & unquote

This is an abomination, but it works
This commit is contained in:
Roman Godmaire 2024-05-05 10:28:24 -04:00
parent 66a2905c60
commit e9c350e925
2 changed files with 47 additions and 0 deletions

44
src/env/core.rs vendored
View file

@ -43,6 +43,50 @@ pub(super) fn core() -> HashMap<String, Node> {
Ok(val) 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<Node> = 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::<Result<Vec<Node>, _>>()?;
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 // Arithmetic operations
( (
"+", "+",

View file

@ -97,9 +97,12 @@ mod test {
#[case("(eval (list + 1 1))", "2")] #[case("(eval (list + 1 1))", "2")]
#[case("(apply + (list 1 2 3))", "6")] #[case("(apply + (list 1 2 3))", "6")]
#[case("'(1 2 3)", "(1 2 3)")] #[case("'(1 2 3)", "(1 2 3)")]
// Quoting
#[case("(quote (1 2 3))", "(1 2 3)")] #[case("(quote (1 2 3))", "(1 2 3)")]
#[case("'(1 2 (4 5) 6 7)", "(1 2 (4 5) 6 7)")] #[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("(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 // Arithmetic
#[case("(+ 1 2)", "3")] #[case("(+ 1 2)", "3")]
#[case("(- 5 1)", "4")] #[case("(- 5 1)", "4")]