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)
|
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
|
||||||
(
|
(
|
||||||
"+",
|
"+",
|
||||||
|
|
|
@ -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")]
|
||||||
|
|
Loading…
Reference in a new issue