feat: quasiquote & unquote
This is an abomination, but it works
This commit is contained in:
parent
66a2905c60
commit
e9c350e925
2 changed files with 47 additions and 0 deletions
44
src/env/core.rs
vendored
44
src/env/core.rs
vendored
|
@ -43,6 +43,50 @@ pub(super) fn core() -> HashMap<String, Node> {
|
|||
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
|
||||
(
|
||||
"+",
|
||||
|
|
|
@ -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")]
|
||||
|
|
Loading…
Reference in a new issue