diff --git a/dsk/lib/lisp/core.lsp b/dsk/lib/lisp/core.lsp index c46c22af4..43ac82f27 100644 --- a/dsk/lib/lisp/core.lsp +++ b/dsk/lib/lisp/core.lsp @@ -61,10 +61,6 @@ (f (first ls)) (map f (rest ls))))) -(def (append x y) - (if (nil? x) y - (cons (first x) (append (rest x) y)))) - (def (reverse x) (if (nil? x) x (append (reverse (rest x)) (cons (first x) '())))) diff --git a/src/usr/lisp/env.rs b/src/usr/lisp/env.rs index 6451a48a0..802d315fb 100644 --- a/src/usr/lisp/env.rs +++ b/src/usr/lisp/env.rs @@ -3,7 +3,6 @@ use super::eval::BUILT_INS; use super::eval::eval_args; use super::list_of_bytes; use super::list_of_numbers; -use super::list_of_symbols; use super::parse::parse; use super::{Err, Exp, Number}; use super::{float, number, string}; @@ -265,13 +264,14 @@ pub fn default_env() -> Rc> { data.insert("type".to_string(), Exp::Primitive(|args: &[Exp]| -> Result { ensure_length_eq!(args, 1); let exp = match args[0] { - Exp::Str(_) => "string", - Exp::Bool(_) => "boolean", - Exp::Sym(_) => "symbol", - Exp::Num(_) => "number", - Exp::List(_) => "list", Exp::Primitive(_) => "function", - Exp::Lambda(_) => "function", + Exp::Function(_) => "function", + Exp::Macro(_) => "macro", + Exp::List(_) => "list", + Exp::Bool(_) => "boolean", + Exp::Str(_) => "string", + Exp::Sym(_) => "symbol", + Exp::Num(_) => "number", }; Ok(Exp::Str(exp.to_string())) })); @@ -284,15 +284,26 @@ pub fn default_env() -> Rc> { _ => Err(Err::Reason("Expected arg to be a number".to_string())) } })); - data.insert("list".to_string(), Exp::Primitive(|args: &[Exp]| -> Result { - Ok(Exp::List(args.to_vec())) - })); data.insert("parse".to_string(), Exp::Primitive(|args: &[Exp]| -> Result { ensure_length_eq!(args, 1); let s = string(&args[0])?; let (_, exp) = parse(&s)?; Ok(exp) })); + data.insert("list".to_string(), Exp::Primitive(|args: &[Exp]| -> Result { + Ok(Exp::List(args.to_vec())) + })); + data.insert("append".to_string(), Exp::Primitive(|args: &[Exp]| -> Result { + let mut res = vec![]; + for arg in args { + if let Exp::List(list) = arg { + res.extend_from_slice(&list); + } else { + return Err(Err::Reason("Expected arg to be a list".to_string())) + } + } + Ok(Exp::List(res)) + })); // Setup autocompletion *FORMS.lock() = data.keys().cloned().chain(BUILT_INS.map(String::from)).collect(); @@ -329,16 +340,40 @@ pub fn env_set(key: &str, val: Exp, env: &Rc>) -> Result<(), Err> { } } -pub fn lambda_env(params: &Exp, args: &[Exp], outer: &mut Rc>) -> Result>, Err> { - let ks = list_of_symbols(params)?; - if ks.len() != args.len() { - let plural = if ks.len() == 1 { "" } else { "s" }; - return Err(Err::Reason(format!("Expected {} argument{}, got {}", ks.len(), plural, args.len()))); - } - let vs = eval_args(args, outer)?; +enum InnerEnv { Function, Macro } + +fn inner_env(kind: InnerEnv, params: &Exp, args: &[Exp], outer: &mut Rc>) -> Result>, Err> { + let args = match kind { + InnerEnv::Function => eval_args(args, outer)?, + InnerEnv::Macro => args.to_vec(), + }; let mut data: BTreeMap = BTreeMap::new(); - for (k, v) in ks.iter().zip(vs.iter()) { - data.insert(k.clone(), v.clone()); + match params { + Exp::Sym(s) => { + data.insert(s.clone(), Exp::List(args)); + } + Exp::List(list) => { + if list.len() != args.len() { + let plural = if list.len() == 1 { "" } else { "s" }; + return Err(Err::Reason(format!("Expected {} argument{}, got {}", list.len(), plural, args.len()))); + } + for (exp, arg) in list.iter().zip(args.iter()) { + if let Exp::Sym(s) = exp { + data.insert(s.clone(), arg.clone()); + } else { + return Err(Err::Reason("Expected symbols in the argument list".to_string())); + } + } + } + _ => return Err(Err::Reason("Expected args form to be a list".to_string())), } Ok(Rc::new(RefCell::new(Env { data, outer: Some(Rc::new(RefCell::new(outer.borrow_mut().clone()))) }))) } + +pub fn function_env(params: &Exp, args: &[Exp], outer: &mut Rc>) -> Result>, Err> { + inner_env(InnerEnv::Function, params, args, outer) +} + +pub fn macro_env(params: &Exp, args: &[Exp], outer: &mut Rc>) -> Result>, Err> { + inner_env(InnerEnv::Macro, params, args, outer) +} diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index aace6b11b..e81fdf3c2 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -1,6 +1,7 @@ -use super::{Err, Exp, Env, Lambda}; -use super::env::{env_get, env_set, lambda_env}; +use super::{Err, Exp, Env, Function}; +use super::env::{env_get, env_set, function_env}; use super::parse::parse; +use super::expand::expand; use super::string; use crate::{ensure_length_eq, ensure_length_gt}; @@ -67,25 +68,7 @@ fn eval_cons_args(args: &[Exp], env: &mut Rc>) -> Result } } -// TODO: Remove this when macro is enabled -fn eval_cond_args(args: &[Exp], env: &mut Rc>) -> Result { - ensure_length_gt!(args, 0); - for arg in args { - match arg { - Exp::List(list) => { - ensure_length_eq!(list, 2); - match eval(&list[0], env)? { - Exp::Bool(b) if b => return eval(&list[1], env), - _ => continue, - } - }, - _ => return Err(Err::Reason("Expected lists of predicate and expression".to_string())), - } - } - Ok(Exp::List(vec![])) -} - -pub fn eval_label_args(args: &[Exp], env: &mut Rc>) -> Result { +pub fn eval_define_args(args: &[Exp], env: &mut Rc>) -> Result { ensure_length_eq!(args, 2); match &args[0] { Exp::Sym(name) => { @@ -93,17 +76,7 @@ pub fn eval_label_args(args: &[Exp], env: &mut Rc>) -> Result { - // (label (add x y) (+ x y)) => (label add (lambda (x y) (+ x y))) - ensure_length_gt!(params, 0); - let name = params[0].clone(); - let params = Exp::List(params[1..].to_vec()); - let body = args[1].clone(); - let lambda_args = vec![Exp::Sym("lambda".to_string()), params, body]; - let label_args = vec![name, Exp::List(lambda_args)]; - eval_label_args(&label_args, env) - } - _ => Err(Err::Reason("Expected first argument to be a symbol or a list".to_string())) + _ => Err(Err::Reason("Expected first argument to be a symbol".to_string())) } } @@ -131,18 +104,6 @@ fn eval_while_args(args: &[Exp], env: &mut Rc>) -> Result Ok(res) } -// TODO: Remove this when macro is enabled -fn eval_defun_args(args: &[Exp], env: &mut Rc>) -> Result { - // (defun add (x y) (+ x y)) => (label add (lambda (x y) (+ x y))) - ensure_length_eq!(args, 3); - let name = args[0].clone(); - let params = args[1].clone(); - let body = args[2].clone(); - let lambda_args = vec![Exp::Sym("lambda".to_string()), params, body]; - let label_args = vec![name, Exp::List(lambda_args)]; - eval_label_args(&label_args, env) -} - fn eval_apply_args(args: &[Exp], env: &mut Rc>) -> Result { ensure_length_gt!(args, 1); let mut args = args.to_vec(); @@ -159,7 +120,7 @@ fn eval_eval_args(args: &[Exp], env: &mut Rc>) -> Result eval(&exp, env) } -fn eval_progn_args(args: &[Exp], env: &mut Rc>) -> Result { +fn eval_do_args(args: &[Exp], env: &mut Rc>) -> Result { let mut res = Ok(Exp::List(vec![])); for arg in args { res = Ok(eval(arg, env)?); @@ -173,6 +134,7 @@ fn eval_load_args(args: &[Exp], env: &mut Rc>) -> Result let mut code = fs::read_to_string(&path).or(Err(Err::Reason("Could not read file".to_string())))?; loop { let (rest, exp) = parse(&code)?; + let exp = expand(&exp, env)?; eval(&exp, env)?; if rest.is_empty() { break; @@ -213,20 +175,17 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { Exp::Sym(s) if s == "car" => return eval_car_args(args, env), Exp::Sym(s) if s == "cdr" => return eval_cdr_args(args, env), Exp::Sym(s) if s == "cons" => return eval_cons_args(args, env), - Exp::Sym(s) if s == "cond" => return eval_cond_args(args, env), Exp::Sym(s) if s == "set" => return eval_set_args(args, env), Exp::Sym(s) if s == "while" => return eval_while_args(args, env), - Exp::Sym(s) if s == "defun" => return eval_defun_args(args, env), - Exp::Sym(s) if s == "defn" => return eval_defun_args(args, env), Exp::Sym(s) if s == "apply" => return eval_apply_args(args, env), Exp::Sym(s) if s == "eval" => return eval_eval_args(args, env), - Exp::Sym(s) if s == "progn" => return eval_progn_args(args, env), - Exp::Sym(s) if s == "begin" => return eval_progn_args(args, env), - Exp::Sym(s) if s == "do" => return eval_progn_args(args, env), + Exp::Sym(s) if s == "do" => return eval_do_args(args, env), Exp::Sym(s) if s == "load" => return eval_load_args(args, env), - Exp::Sym(s) if s == "label" => return eval_label_args(args, env), - Exp::Sym(s) if s == "define" => return eval_label_args(args, env), - Exp::Sym(s) if s == "def" => return eval_label_args(args, env), + Exp::Sym(s) if s == "define" => return eval_define_args(args, env), + Exp::Sym(s) if s == "expand" => { + ensure_length_eq!(args, 1); + return expand(&args[0], env); + } Exp::Sym(s) if s == "if" => { ensure_length_gt!(args, 1); if eval(&args[0], env)? == Exp::Bool(true) { // consequent @@ -238,17 +197,24 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { } exp = &exp_tmp; } - Exp::Sym(s) if s == "lambda" || s == "function" || s == "fun" || s == "fn" => { + Exp::Sym(s) if s == "function" => { + ensure_length_eq!(args, 2); + return Ok(Exp::Function(Box::new(Function { + params: args[0].clone(), + body: args[1].clone(), + }))) + } + Exp::Sym(s) if s == "macro" => { ensure_length_eq!(args, 2); - return Ok(Exp::Lambda(Box::new(Lambda { + return Ok(Exp::Macro(Box::new(Function { params: args[0].clone(), body: args[1].clone(), }))) } _ => { match eval(&list[0], env)? { - Exp::Lambda(f) => { - env_tmp = lambda_env(&f.params, args, env)?; + Exp::Function(f) => { + env_tmp = function_env(&f.params, args, env)?; exp_tmp = f.body; env = &mut env_tmp; exp = &exp_tmp; @@ -261,8 +227,7 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { } } }, - Exp::Primitive(_) => return Err(Err::Reason("Unexpected form".to_string())), - Exp::Lambda(_) => return Err(Err::Reason("Unexpected form".to_string())), + _ => return Err(Err::Reason("Unexpected form".to_string())), } } } diff --git a/src/usr/lisp/expand.rs b/src/usr/lisp/expand.rs new file mode 100644 index 000000000..d6c6b790a --- /dev/null +++ b/src/usr/lisp/expand.rs @@ -0,0 +1,143 @@ +use super::{Err, Exp, Env}; +use super::env::{env_get, macro_env}; +use super::eval::eval; + +use crate::{ensure_length_eq, ensure_length_gt}; + +use alloc::format; +use alloc::rc::Rc; +use alloc::string::ToString; +use alloc::vec::Vec; +use alloc::vec; +use core::cell::RefCell; + +pub fn expand_quasiquote(exp: &Exp) -> Result { + match exp { + Exp::List(list) if list.len() > 0 => { + match &list[0] { + Exp::Sym(s) if s == "unquote" => { + Ok(list[1].clone()) + } + Exp::List(l) if l.len() == 2 && l[0] == Exp::Sym("unquote-splicing".to_string()) => { + Ok(Exp::List(vec![ + Exp::Sym("append".to_string()), + l[1].clone(), + expand_quasiquote(&Exp::List(list[1..].to_vec()))? + ])) + } + _ => { + Ok(Exp::List(vec![ + Exp::Sym("cons".to_string()), + expand_quasiquote(&list[0])?, + expand_quasiquote(&Exp::List(list[1..].to_vec()))?, + ])) + } + } + } + _ => Ok(Exp::List(vec![Exp::Sym("quote".to_string()), exp.clone()])), + } +} + +pub fn expand_list(list: &[Exp], env: &mut Rc>) -> Result { + let expanded: Result, Err> = list.iter().map(|item| expand(item, env)).collect(); + Ok(Exp::List(expanded?)) +} + +pub fn expand(exp: &Exp, env: &mut Rc>) -> Result { + if let Exp::List(list) = exp { + ensure_length_gt!(list, 0); + match &list[0] { + Exp::Sym(s) if s == "quote" => { + ensure_length_eq!(list, 2); + Ok(exp.clone()) + } + Exp::Sym(s) if s == "quasiquote" => { + ensure_length_eq!(list, 2); + expand_quasiquote(&list[1]) + } + Exp::Sym(s) if s == "begin" || s == "progn" => { + let mut res = vec![Exp::Sym("do".to_string())]; + res.extend_from_slice(&list[1..]); + expand(&Exp::List(res), env) + } + Exp::Sym(s) if s == "def" || s == "label" => { + let mut res = vec![Exp::Sym("define".to_string())]; + res.extend_from_slice(&list[1..]); + expand(&Exp::List(res), env) + } + Exp::Sym(s) if s == "fun" || s == "fn" || s == "lambda" => { + let mut res = vec![Exp::Sym("function".to_string())]; + res.extend_from_slice(&list[1..]); + expand(&Exp::List(res), env) + } + Exp::Sym(s) if s == "mac" => { + let mut res = vec![Exp::Sym("macro".to_string())]; + res.extend_from_slice(&list[1..]); + expand(&Exp::List(res), env) + } + Exp::Sym(s) if s == "define-function" || s == "def-fun" || s == "define" => { + ensure_length_eq!(list, 3); + match (&list[1], &list[2]) { + (Exp::List(args), Exp::List(_)) => { + ensure_length_gt!(args, 0); + let name = args[0].clone(); + let args = Exp::List(args[1..].to_vec()); + let body = expand(&list[2], env)?; + Ok(Exp::List(vec![ + Exp::Sym("define".to_string()), name, Exp::List(vec![ + Exp::Sym("function".to_string()), args, body + ]) + ])) + } + (Exp::Sym(_), _) => expand_list(list, env), + _ => Err(Err::Reason("Expected first argument to be a symbol or a list".to_string())) + } + } + Exp::Sym(s) if s == "define-macro" || s == "def-mac" => { + ensure_length_eq!(list, 3); + match (&list[1], &list[2]) { + (Exp::List(args), Exp::List(_)) => { + ensure_length_gt!(args, 0); + let name = args[0].clone(); + let args = Exp::List(args[1..].to_vec()); + let body = expand(&list[2], env)?; + Ok(Exp::List(vec![ + Exp::Sym("define".to_string()), name, Exp::List(vec![ + Exp::Sym("macro".to_string()), args, body + ]) + ])) + } + (Exp::Sym(_), _) => expand_list(list, env), + _ => Err(Err::Reason("Expected first argument to be a symbol or a list".to_string())) + } + } + Exp::Sym(s) if s == "cond" => { + ensure_length_gt!(list, 1); + if let Exp::List(args) = &list[1] { + ensure_length_eq!(args, 2); + let mut res = vec![Exp::Sym("if".to_string()), args[0].clone(), args[1].clone()]; + if list.len() > 2 { + let mut acc = vec![Exp::Sym("cond".to_string())]; + acc.extend_from_slice(&list[2..]); + res.push(expand(&Exp::List(acc), env)?); + } + Ok(Exp::List(res)) + } else { + Err(Err::Reason("Expected lists of predicate and expression".to_string())) + } + } + Exp::Sym(s) => { + if let Ok(Exp::Macro(m)) = env_get(s, env) { + let mut m_env = macro_env(&m.params, &list[1..], env)?; + let m_exp = m.body; + expand(&eval(&m_exp, &mut m_env)?, env) + } else { + expand_list(list, env) + } + } + _ => expand_list(list, env), + } + } else { + Ok(exp.clone()) + } +} diff --git a/src/usr/lisp/mod.rs b/src/usr/lisp/mod.rs index 872c036c9..0434c22e3 100644 --- a/src/usr/lisp/mod.rs +++ b/src/usr/lisp/mod.rs @@ -1,5 +1,6 @@ mod env; mod eval; +mod expand; mod number; mod parse; @@ -7,7 +8,8 @@ pub use number::Number; pub use env::Env; use env::default_env; -use eval::{eval, eval_label_args}; +use eval::{eval, eval_define_args}; +use expand::expand; use parse::parse; use crate::api; @@ -46,7 +48,8 @@ use spin::Mutex; #[derive(Clone)] pub enum Exp { Primitive(fn(&[Exp]) -> Result), - Lambda(Box), + Function(Box), + Macro(Box), List(Vec), Bool(bool), Num(Number), @@ -57,12 +60,13 @@ pub enum Exp { impl PartialEq for Exp { fn eq(&self, other: &Self) -> bool { match (self, other) { - (Exp::Lambda(a), Exp::Lambda(b)) => a == b, - (Exp::List(a), Exp::List(b)) => a == b, - (Exp::Bool(a), Exp::Bool(b)) => a == b, - (Exp::Num(a), Exp::Num(b)) => a == b, - (Exp::Str(a), Exp::Str(b)) => a == b, - (Exp::Sym(a), Exp::Sym(b)) => a == b, + (Exp::Function(a), Exp::Function(b)) => a == b, + (Exp::Macro(a), Exp::Macro(b)) => a == b, + (Exp::List(a), Exp::List(b)) => a == b, + (Exp::Bool(a), Exp::Bool(b)) => a == b, + (Exp::Num(a), Exp::Num(b)) => a == b, + (Exp::Str(a), Exp::Str(b)) => a == b, + (Exp::Sym(a), Exp::Sym(b)) => a == b, _ => false, } } @@ -72,7 +76,8 @@ impl fmt::Display for Exp { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let out = match self { Exp::Primitive(_) => "".to_string(), - Exp::Lambda(_) => "".to_string(), + Exp::Function(_) => "".to_string(), + Exp::Macro(_) => "".to_string(), Exp::Bool(a) => a.to_string(), Exp::Num(n) => n.to_string(), Exp::Sym(s) => s.clone(), @@ -87,7 +92,7 @@ impl fmt::Display for Exp { } #[derive(Clone, PartialEq)] -pub struct Lambda { +pub struct Function { params: Exp, body: Exp, } @@ -121,20 +126,6 @@ macro_rules! ensure_length_gt { }; } -fn list_of_symbols(form: &Exp) -> Result, Err> { - match form { - Exp::List(list) => { - list.iter().map(|exp| { - match exp { - Exp::Sym(sym) => Ok(sym.clone()), - _ => Err(Err::Reason("Expected symbols in the argument list".to_string())) - } - }).collect() - } - _ => Err(Err::Reason("Expected args form to be a list".to_string())) - } -} - pub fn list_of_numbers(args: &[Exp]) -> Result, Err> { args.iter().map(number).collect() } @@ -172,6 +163,7 @@ pub fn byte(exp: &Exp) -> Result { fn parse_eval(exp: &str, env: &mut Rc>) -> Result { let (_, exp) = parse(exp)?; + let exp = expand(&exp, env)?; let exp = eval(&exp, env)?; Ok(exp) } @@ -244,7 +236,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> { args[2..].iter().map(|arg| Exp::Str(arg.to_string())).collect() }); let quote = Exp::List(vec![Exp::Sym("quote".to_string()), list]); - if eval_label_args(&[key, quote], env).is_err() { + if eval_define_args(&[key, quote], env).is_err() { error!("Could not parse args"); return Err(ExitCode::Failure); } @@ -353,24 +345,24 @@ fn test_lisp() { // while assert_eq!(eval!("(do (def i 0) (while (< i 5) (set i (+ i 1))) i)"), "5"); - // label - eval!("(label a 2)"); + // define + eval!("(define a 2)"); assert_eq!(eval!("(+ a 1)"), "3"); - //eval!("(label fn lambda)"); - //assert_eq!(eval!("((fn (a) (+ 1 a)) 2)"), "3"); - eval!("(label add-one (lambda (b) (+ b 1)))"); + eval!("(define add-one (function (b) (+ b 1)))"); assert_eq!(eval!("(add-one 2)"), "3"); - eval!("(label fib (lambda (n) (cond ((< n 2) n) (true (+ (fib (- n 1)) (fib (- n 2)))))))"); - assert_eq!(eval!("(fib 6)"), "8"); + eval!("(define fibonacci (function (n) (if (< n 2) n (+ (fibonacci (- n 1)) (fibonacci (- n 2))))))"); + assert_eq!(eval!("(fibonacci 6)"), "8"); - // lambda - assert_eq!(eval!("((lambda (a) (+ 1 a)) 2)"), "3"); - assert_eq!(eval!("((lambda (a) (* a a)) 2)"), "4"); - assert_eq!(eval!("((lambda (x) (cons x '(b c))) 'a)"), "(a b c)"); + // function + assert_eq!(eval!("((function (a) (+ 1 a)) 2)"), "3"); + assert_eq!(eval!("((function (a) (* a a)) 2)"), "4"); + assert_eq!(eval!("((function (x) (cons x '(b c))) 'a)"), "(a b c)"); - // defun - eval!("(defun add (a b) (+ a b))"); - assert_eq!(eval!("(add 1 2)"), "3"); + // function definition shortcut + eval!("(define (double x) (* x 2))"); + assert_eq!(eval!("(double 2)"), "4"); + eval!("(define-function (triple x) (* x 3))"); + assert_eq!(eval!("(triple 2)"), "6"); // addition assert_eq!(eval!("(+)"), "0"); @@ -469,4 +461,24 @@ fn test_lisp() { assert_eq!(eval!("(number-type 9223372036854775807)"), "\"int\""); assert_eq!(eval!("(number-type 9223372036854775808)"), "\"bigint\""); assert_eq!(eval!("(number-type 9223372036854776000.0)"), "\"float\""); + + // quasiquote + eval!("(define x 'a)"); + assert_eq!(eval!("`(x ,x y)"), "(x a y)"); + assert_eq!(eval!("`(x ,x y ,(+ 1 2))"), "(x a y 3)"); + + // unquote-splicing + eval!("(define x '(1 2 3))"); + assert_eq!(eval!("`(+ ,x)"), "(+ (1 2 3))"); + assert_eq!(eval!("`(+ ,@x)"), "(+ 1 2 3)"); + + // macro + eval!("(define foo 42)"); + eval!("(define set-10 (macro (x) `(set ,x 10)))"); + eval!("(set-10 foo)"); + assert_eq!(eval!("foo"), "10"); + + // args + eval!("(define list* (function args (append args '())))"); + assert_eq!(eval!("(list* 1 2 3)"), "(1 2 3)"); } diff --git a/src/usr/lisp/parse.rs b/src/usr/lisp/parse.rs index fa983f8b8..58f241dfb 100644 --- a/src/usr/lisp/parse.rs +++ b/src/usr/lisp/parse.rs @@ -67,8 +67,28 @@ fn parse_quote(input: &str) -> IResult<&str, Exp> { Ok((input, Exp::List(list))) } +fn parse_unquote_splicing(input: &str) -> IResult<&str, Exp> { + let (input, list) = preceded(tag(",@"), parse_exp)(input)?; + let list = vec![Exp::Sym("unquote-splicing".to_string()), list]; + Ok((input, Exp::List(list))) +} + +fn parse_unquote(input: &str) -> IResult<&str, Exp> { + let (input, list) = preceded(char(','), parse_exp)(input)?; + let list = vec![Exp::Sym("unquote".to_string()), list]; + Ok((input, Exp::List(list))) +} + +fn parse_quasiquote(input: &str) -> IResult<&str, Exp> { + let (input, list) = preceded(char('`'), parse_exp)(input)?; + let list = vec![Exp::Sym("quasiquote".to_string()), list]; + Ok((input, Exp::List(list))) +} + fn parse_exp(input: &str) -> IResult<&str, Exp> { - delimited(multispace0, alt((parse_num, parse_bool, parse_str, parse_list, parse_quote, parse_sym)), multispace0)(input) + delimited(multispace0, alt(( + parse_num, parse_bool, parse_str, parse_list, parse_quote, parse_unquote_splicing, parse_unquote, parse_quasiquote, parse_sym + )), multispace0)(input) } pub fn parse(input: &str)-> Result<(String, Exp), Err> {