From e712e92b56129aba3adb8c59712bd17880172e53 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 21 Oct 2022 22:33:46 +0200 Subject: [PATCH 01/16] Add TCO to Lisp --- src/usr/lisp/eval.rs | 155 ++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 83 deletions(-) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index 7124871cd..792570243 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -83,17 +83,6 @@ fn eval_cond_args(args: &[Exp], env: &mut Rc>) -> Result Ok(Exp::List(vec![])) } -fn eval_if_args(args: &[Exp], env: &mut Rc>) -> Result { - ensure_length_gt!(args, 1); - if eval(&args[0], env)? == Exp::Bool(true) { - eval(&args[1], env) - } else if args.len() > 2 { - eval(&args[2], env) - } else { - Ok(Exp::List(vec![])) - } -} - pub fn eval_label_args(args: &[Exp], env: &mut Rc>) -> Result { ensure_length_eq!(args, 2); match &args[0] { @@ -140,14 +129,6 @@ fn eval_while_args(args: &[Exp], env: &mut Rc>) -> Result Ok(res) } -fn eval_lambda_args(args: &[Exp]) -> Result { - ensure_length_eq!(args, 2); - Ok(Exp::Lambda(Lambda { - params: Rc::new(args[0].clone()), - body: Rc::new(args[1].clone()), - })) -} - 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); @@ -198,76 +179,84 @@ fn eval_load_args(args: &[Exp], env: &mut Rc>) -> Result Ok(Exp::Bool(true)) } -pub const BUILT_INS: [&str; 24] = [ - "quote", "atom", "eq", "car", "cdr", "cons", "cond", "label", "lambda", "define", "def", - "function", "fun", "fn", "if", "while", "defun", "defn", "apply", "eval", "progn", "begin", "do", - "load" -]; - -fn eval_built_in_form(exp: &Exp, args: &[Exp], env: &mut Rc>) -> Option> { - match exp { - Exp::Sym(s) => { - match s.as_ref() { - // Seven Primitive Operators - "quote" => Some(eval_quote_args(args)), - "atom" => Some(eval_atom_args(args, env)), - "eq" => Some(eval_eq_args(args, env)), - "car" => Some(eval_car_args(args, env)), - "cdr" => Some(eval_cdr_args(args, env)), - "cons" => Some(eval_cons_args(args, env)), - "cond" => Some(eval_cond_args(args, env)), - - // Two Special Forms - "label" | "define" | "def" => Some(eval_label_args(args, env)), - "lambda" | "function" | "fun" | "fn" => Some(eval_lambda_args(args)), - - "if" => Some(eval_if_args(args, env)), - "set" => Some(eval_set_args(args, env)), - "while" => Some(eval_while_args(args, env)), - "defun" | "defn" => Some(eval_defun_args(args, env)), - "apply" => Some(eval_apply_args(args, env)), - "eval" => Some(eval_eval_args(args, env)), - "progn" | "begin" | "do" => Some(eval_progn_args(args, env)), - "load" => Some(eval_load_args(args, env)), - _ => None, - } - }, - _ => None, - } -} - pub fn eval_args(args: &[Exp], env: &mut Rc>) -> Result, Err> { args.iter().map(|x| eval(x, env)).collect() } +pub const BUILT_INS: [&str; 24] = [ + "quote", "atom", "eq", "car", "cdr", "cons", "cond", "label", "lambda", "define", "def", + "function", "fun", "fn", "if", "while", "defun", "defn", "apply", "eval", "progn", "begin", + "do", "load" +]; + pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { - match exp { - Exp::Sym(key) => env_get(key, env), - Exp::Bool(_) => Ok(exp.clone()), - Exp::Num(_) => Ok(exp.clone()), - Exp::Str(_) => Ok(exp.clone()), - Exp::List(list) => { - ensure_length_gt!(list, 0); - let first_form = &list[0]; - let args = &list[1..]; - match eval_built_in_form(first_form, args, env) { - Some(res) => res, - None => { - let first_eval = eval(first_form, env)?; - match first_eval { - Exp::Primitive(f) => { - f(&eval_args(args, env)?) - }, - Exp::Lambda(f) => { - let mut env = lambda_env(f.params, args, env)?; - eval(&f.body, &mut env) - }, - _ => Err(Err::Reason("First form must be a function".to_string())), + let mut env = env.clone(); + let mut exp = exp.clone(); + loop { + match exp.clone() { + Exp::Sym(key) => return env_get(&key, &mut env), + Exp::Bool(_) => return Ok(exp.clone()), + Exp::Num(_) => return Ok(exp.clone()), + Exp::Str(_) => return Ok(exp.clone()), + Exp::List(list) => { + ensure_length_gt!(list, 0); + let first_form = &list[0]; + let args = &list[1..]; + match first_form { + Exp::Sym(s) if s == "quote" => return eval_quote_args(args), + Exp::Sym(s) if s == "atom" => return eval_atom_args(args, &mut env), + Exp::Sym(s) if s == "eq" => return eval_eq_args(args, &mut env), + Exp::Sym(s) if s == "car" => return eval_car_args(args, &mut env), + Exp::Sym(s) if s == "cdr" => return eval_cdr_args(args, &mut env), + Exp::Sym(s) if s == "cons" => return eval_cons_args(args, &mut env), + Exp::Sym(s) if s == "cond" => return eval_cond_args(args, &mut env), + Exp::Sym(s) if s == "set" => return eval_set_args(args, &mut env), + Exp::Sym(s) if s == "while" => return eval_while_args(args, &mut env), + Exp::Sym(s) if s == "defun" => return eval_defun_args(args, &mut env), + Exp::Sym(s) if s == "defn" => return eval_defun_args(args, &mut env), + Exp::Sym(s) if s == "apply" => return eval_apply_args(args, &mut env), + Exp::Sym(s) if s == "eval" => return eval_eval_args(args, &mut env), + Exp::Sym(s) if s == "progn" => return eval_progn_args(args, &mut env), + Exp::Sym(s) if s == "begin" => return eval_progn_args(args, &mut env), + Exp::Sym(s) if s == "do" => return eval_progn_args(args, &mut env), + Exp::Sym(s) if s == "load" => return eval_load_args(args, &mut env), + Exp::Sym(s) if s == "label" => return eval_label_args(args, &mut env), + Exp::Sym(s) if s == "define" => return eval_label_args(args, &mut env), + Exp::Sym(s) if s == "def" => return eval_label_args(args, &mut env), + Exp::Sym(s) if s == "lambda" || s == "function" || s == "fun" || s == "fn" => { + ensure_length_eq!(args, 2); + return Ok(Exp::Lambda(Lambda { + params: Rc::new(args[0].clone()), + body: Rc::new(args[1].clone()), + })) + } + Exp::Sym(s) if s == "if" => { + ensure_length_gt!(args, 1); + if eval(&args[0], &mut env)? == Exp::Bool(true) { + exp = args[1].clone(); + } else if args.len() > 2 { + exp = args[2].clone(); + } else { + exp = Exp::List(vec![]); + } + } + _ => { + let first_eval = eval(first_form, &mut env)?; + match first_eval { + Exp::Primitive(f) => { + return f(&eval_args(args, &mut env)?) + }, + Exp::Lambda(f) => { + env = lambda_env(f.params, args, &mut env)?; + exp = (*f.body).clone(); + }, + _ => return Err(Err::Reason("First form must be a function".to_string())), + } } } - } - }, - Exp::Primitive(_) => Err(Err::Reason("Unexpected form".to_string())), - Exp::Lambda(_) => Err(Err::Reason("Unexpected form".to_string())), + }, + Exp::Primitive(_) => return Err(Err::Reason("Unexpected form".to_string())), + Exp::Lambda(_) => return Err(Err::Reason("Unexpected form".to_string())), + } } } From 3ecf5f6de8f847ccb75173e17810cc4291880960 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 21 Oct 2022 22:37:17 +0200 Subject: [PATCH 02/16] Add sum.lsp --- dsk/tmp/lisp/sum.lsp | 8 ++++++++ src/usr/install.rs | 1 + 2 files changed, 9 insertions(+) create mode 100644 dsk/tmp/lisp/sum.lsp diff --git a/dsk/tmp/lisp/sum.lsp b/dsk/tmp/lisp/sum.lsp new file mode 100644 index 000000000..abf1bc796 --- /dev/null +++ b/dsk/tmp/lisp/sum.lsp @@ -0,0 +1,8 @@ +(load "/lib/lisp/core.lsp") + +(def (sum n acc) + (if (= n 0) acc (sum (- n 1) (+ n acc)))) + +(println + (if (nil? args) "Usage: sum " + (sum (string->number (car args)) 0))) diff --git a/src/usr/install.rs b/src/usr/install.rs index 4c42deaa4..64e81f3bc 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -56,6 +56,7 @@ pub fn copy_files(verbose: bool) { copy_file("/tmp/lisp/factorial.lsp", include_bytes!("../../dsk/tmp/lisp/factorial.lsp"), verbose); copy_file("/tmp/lisp/fibonacci.lsp", include_bytes!("../../dsk/tmp/lisp/fibonacci.lsp"), verbose); copy_file("/tmp/lisp/pi.lsp", include_bytes!("../../dsk/tmp/lisp/pi.lsp"), verbose); + copy_file("/tmp/lisp/sum.lsp", include_bytes!("../../dsk/tmp/lisp/sum.lsp"), verbose); create_dir("/tmp/life", verbose); copy_file("/tmp/life/centinal.cells", include_bytes!("../../dsk/tmp/life/centinal.cells"), verbose); From c4a9c9ccaf56c64753d0e793f01a835f459a657b Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 21 Oct 2022 23:14:58 +0200 Subject: [PATCH 03/16] Fix tests --- src/usr/lisp/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index 792570243..3a7ed3b8b 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -237,7 +237,7 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { } else if args.len() > 2 { exp = args[2].clone(); } else { - exp = Exp::List(vec![]); + exp = Exp::List(vec![Exp::Sym("quote".to_string()), Exp::List(vec![])]); } } _ => { From a6f65b8f5d31f28500c76ec79d22cc26ae981e0c Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 21 Oct 2022 23:57:26 +0200 Subject: [PATCH 04/16] Refactor code --- src/usr/lisp/eval.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index 3a7ed3b8b..20c03364b 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -200,9 +200,8 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { Exp::Str(_) => return Ok(exp.clone()), Exp::List(list) => { ensure_length_gt!(list, 0); - let first_form = &list[0]; let args = &list[1..]; - match first_form { + match &list[0] { Exp::Sym(s) if s == "quote" => return eval_quote_args(args), Exp::Sym(s) if s == "atom" => return eval_atom_args(args, &mut env), Exp::Sym(s) if s == "eq" => return eval_eq_args(args, &mut env), @@ -232,17 +231,16 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { } Exp::Sym(s) if s == "if" => { ensure_length_gt!(args, 1); - if eval(&args[0], &mut env)? == Exp::Bool(true) { + if eval(&args[0], &mut env)? == Exp::Bool(true) { // consequent exp = args[1].clone(); - } else if args.len() > 2 { + } else if args.len() > 2 { // alternate exp = args[2].clone(); - } else { + } else { // '() exp = Exp::List(vec![Exp::Sym("quote".to_string()), Exp::List(vec![])]); } } _ => { - let first_eval = eval(first_form, &mut env)?; - match first_eval { + match eval(&list[0], &mut env)? { Exp::Primitive(f) => { return f(&eval_args(args, &mut env)?) }, From 3378a56b5e88c8e14cddc001cd0ea00b7ee9bcc7 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 22 Oct 2022 08:47:58 +0200 Subject: [PATCH 05/16] Run clippy --- src/usr/lisp/eval.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index 20c03364b..7262103ee 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -194,10 +194,10 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { let mut exp = exp.clone(); loop { match exp.clone() { - Exp::Sym(key) => return env_get(&key, &mut env), - Exp::Bool(_) => return Ok(exp.clone()), - Exp::Num(_) => return Ok(exp.clone()), - Exp::Str(_) => return Ok(exp.clone()), + Exp::Sym(key) => return env_get(&key, &env), + Exp::Bool(_) => return Ok(exp), + Exp::Num(_) => return Ok(exp), + Exp::Str(_) => return Ok(exp), Exp::List(list) => { ensure_length_gt!(list, 0); let args = &list[1..]; From c9116cd8706d844b90d324abe782b52f36da9c28 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 22 Oct 2022 09:57:36 +0200 Subject: [PATCH 06/16] Use tmp var --- src/usr/lisp/eval.rs | 50 +++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index 7262103ee..d80f1c084 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -190,8 +190,9 @@ pub const BUILT_INS: [&str; 24] = [ ]; pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { - let mut env = env.clone(); let mut exp = exp.clone(); + let mut tmp = env.clone(); + let mut env = &mut tmp; loop { match exp.clone() { Exp::Sym(key) => return env_get(&key, &env), @@ -203,25 +204,25 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { let args = &list[1..]; match &list[0] { Exp::Sym(s) if s == "quote" => return eval_quote_args(args), - Exp::Sym(s) if s == "atom" => return eval_atom_args(args, &mut env), - Exp::Sym(s) if s == "eq" => return eval_eq_args(args, &mut env), - Exp::Sym(s) if s == "car" => return eval_car_args(args, &mut env), - Exp::Sym(s) if s == "cdr" => return eval_cdr_args(args, &mut env), - Exp::Sym(s) if s == "cons" => return eval_cons_args(args, &mut env), - Exp::Sym(s) if s == "cond" => return eval_cond_args(args, &mut env), - Exp::Sym(s) if s == "set" => return eval_set_args(args, &mut env), - Exp::Sym(s) if s == "while" => return eval_while_args(args, &mut env), - Exp::Sym(s) if s == "defun" => return eval_defun_args(args, &mut env), - Exp::Sym(s) if s == "defn" => return eval_defun_args(args, &mut env), - Exp::Sym(s) if s == "apply" => return eval_apply_args(args, &mut env), - Exp::Sym(s) if s == "eval" => return eval_eval_args(args, &mut env), - Exp::Sym(s) if s == "progn" => return eval_progn_args(args, &mut env), - Exp::Sym(s) if s == "begin" => return eval_progn_args(args, &mut env), - Exp::Sym(s) if s == "do" => return eval_progn_args(args, &mut env), - Exp::Sym(s) if s == "load" => return eval_load_args(args, &mut env), - Exp::Sym(s) if s == "label" => return eval_label_args(args, &mut env), - Exp::Sym(s) if s == "define" => return eval_label_args(args, &mut env), - Exp::Sym(s) if s == "def" => return eval_label_args(args, &mut env), + Exp::Sym(s) if s == "atom" => return eval_atom_args(args, env), + Exp::Sym(s) if s == "eq" => return eval_eq_args(args, env), + 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 == "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 == "lambda" || s == "function" || s == "fun" || s == "fn" => { ensure_length_eq!(args, 2); return Ok(Exp::Lambda(Lambda { @@ -231,7 +232,7 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { } Exp::Sym(s) if s == "if" => { ensure_length_gt!(args, 1); - if eval(&args[0], &mut env)? == Exp::Bool(true) { // consequent + if eval(&args[0], env)? == Exp::Bool(true) { // consequent exp = args[1].clone(); } else if args.len() > 2 { // alternate exp = args[2].clone(); @@ -240,12 +241,13 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { } } _ => { - match eval(&list[0], &mut env)? { + match eval(&list[0], env)? { Exp::Primitive(f) => { - return f(&eval_args(args, &mut env)?) + return f(&eval_args(args, env)?) }, Exp::Lambda(f) => { - env = lambda_env(f.params, args, &mut env)?; + tmp = lambda_env(f.params, args, env)?; + env = &mut tmp; exp = (*f.body).clone(); }, _ => return Err(Err::Reason("First form must be a function".to_string())), From d12bda4ad4dd27e9ccd97ccbfa4237305ead32a2 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 22 Oct 2022 16:40:38 +0200 Subject: [PATCH 07/16] Refactor tmp --- src/usr/lisp/eval.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index d80f1c084..5590d7989 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -191,8 +191,8 @@ pub const BUILT_INS: [&str; 24] = [ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { let mut exp = exp.clone(); - let mut tmp = env.clone(); - let mut env = &mut tmp; + let mut env = env; + let mut tmp; loop { match exp.clone() { Exp::Sym(key) => return env_get(&key, &env), From 6c69b304fc44dfdbe49327dbdbfa916e0781c6c5 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 22 Oct 2022 16:56:23 +0200 Subject: [PATCH 08/16] Replace Lambda Rc by Box Lambda --- src/usr/lisp/env.rs | 2 +- src/usr/lisp/eval.rs | 13 +++++++------ src/usr/lisp/mod.rs | 7 ++++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/usr/lisp/env.rs b/src/usr/lisp/env.rs index 6dd90c9f5..ef5b56cdf 100644 --- a/src/usr/lisp/env.rs +++ b/src/usr/lisp/env.rs @@ -329,7 +329,7 @@ pub fn env_set(key: &str, val: Exp, env: &Rc>) -> Result<(), Err> { } } -pub fn lambda_env(params: Rc, args: &[Exp], outer: &mut Rc>) -> Result>, Err> { +pub fn lambda_env(params: &Exp, args: &[Exp], outer: &mut Rc>) -> Result>, Err> { let ks = list_of_symbols(¶ms)?; if ks.len() != args.len() { let plural = if ks.len() == 1 { "" } else { "s" }; diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index 5590d7989..6c8218e78 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -6,6 +6,7 @@ use super::string; use crate::{ensure_length_eq, ensure_length_gt}; use crate::api::fs; +use alloc::boxed::Box; use alloc::format; use alloc::rc::Rc; use alloc::string::ToString; @@ -225,10 +226,10 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { Exp::Sym(s) if s == "def" => return eval_label_args(args, env), Exp::Sym(s) if s == "lambda" || s == "function" || s == "fun" || s == "fn" => { ensure_length_eq!(args, 2); - return Ok(Exp::Lambda(Lambda { - params: Rc::new(args[0].clone()), - body: Rc::new(args[1].clone()), - })) + return Ok(Exp::Lambda(Box::new(Lambda { + params: args[0].clone(), + body: args[1].clone(), + }))) } Exp::Sym(s) if s == "if" => { ensure_length_gt!(args, 1); @@ -246,9 +247,9 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { return f(&eval_args(args, env)?) }, Exp::Lambda(f) => { - tmp = lambda_env(f.params, args, env)?; + tmp = lambda_env(&f.params, args, env)?; env = &mut tmp; - exp = (*f.body).clone(); + exp = f.body.clone(); }, _ => return Err(Err::Reason("First form must be a function".to_string())), } diff --git a/src/usr/lisp/mod.rs b/src/usr/lisp/mod.rs index 5e4208819..872c036c9 100644 --- a/src/usr/lisp/mod.rs +++ b/src/usr/lisp/mod.rs @@ -15,6 +15,7 @@ use crate::api::console::Style; use crate::api::process::ExitCode; use crate::api::prompt::Prompt; +use alloc::boxed::Box; use alloc::format; use alloc::rc::Rc; use alloc::string::String; @@ -45,7 +46,7 @@ use spin::Mutex; #[derive(Clone)] pub enum Exp { Primitive(fn(&[Exp]) -> Result), - Lambda(Lambda), + Lambda(Box), List(Vec), Bool(bool), Num(Number), @@ -87,8 +88,8 @@ impl fmt::Display for Exp { #[derive(Clone, PartialEq)] pub struct Lambda { - params: Rc, - body: Rc, + params: Exp, + body: Exp, } #[derive(Debug)] From 8336294b9905057dfc98a2a542f73d2b22ce9764 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sat, 22 Oct 2022 23:58:57 +0200 Subject: [PATCH 09/16] Remove exp clone --- src/usr/lisp/eval.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index 6c8218e78..227c8571d 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -191,15 +191,16 @@ pub const BUILT_INS: [&str; 24] = [ ]; pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { - let mut exp = exp.clone(); + let mut exp = exp; let mut env = env; - let mut tmp; + let mut env_tmp; + let mut exp_tmp; loop { match exp.clone() { Exp::Sym(key) => return env_get(&key, &env), - Exp::Bool(_) => return Ok(exp), - Exp::Num(_) => return Ok(exp), - Exp::Str(_) => return Ok(exp), + Exp::Bool(_) => return Ok(exp.clone()), + Exp::Num(_) => return Ok(exp.clone()), + Exp::Str(_) => return Ok(exp.clone()), Exp::List(list) => { ensure_length_gt!(list, 0); let args = &list[1..]; @@ -234,12 +235,13 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { Exp::Sym(s) if s == "if" => { ensure_length_gt!(args, 1); if eval(&args[0], env)? == Exp::Bool(true) { // consequent - exp = args[1].clone(); + exp_tmp = args[1].clone(); } else if args.len() > 2 { // alternate - exp = args[2].clone(); + exp_tmp = args[2].clone(); } else { // '() - exp = Exp::List(vec![Exp::Sym("quote".to_string()), Exp::List(vec![])]); + exp_tmp = Exp::List(vec![Exp::Sym("quote".to_string()), Exp::List(vec![])]); } + exp = &exp_tmp; } _ => { match eval(&list[0], env)? { @@ -247,9 +249,10 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { return f(&eval_args(args, env)?) }, Exp::Lambda(f) => { - tmp = lambda_env(&f.params, args, env)?; - env = &mut tmp; - exp = f.body.clone(); + env_tmp = lambda_env(&f.params, args, env)?; + exp_tmp = f.body.clone(); + env = &mut env_tmp; + exp = &exp_tmp; }, _ => return Err(Err::Reason("First form must be a function".to_string())), } From 01f905ce12f2396f86ee043425afe44cf516b99e Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 23 Oct 2022 00:07:21 +0200 Subject: [PATCH 10/16] Run clippy --- src/usr/lisp/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index 227c8571d..f86ec0893 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -197,7 +197,7 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { let mut exp_tmp; loop { match exp.clone() { - Exp::Sym(key) => return env_get(&key, &env), + Exp::Sym(key) => return env_get(&key, env), Exp::Bool(_) => return Ok(exp.clone()), Exp::Num(_) => return Ok(exp.clone()), Exp::Str(_) => return Ok(exp.clone()), From ce28a65376c8b6a4e62dcce764784d3e767aaa52 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 23 Oct 2022 00:59:15 +0200 Subject: [PATCH 11/16] Remove another exp clone --- src/usr/lisp/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index f86ec0893..8b86fab82 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -196,7 +196,7 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { let mut env_tmp; let mut exp_tmp; loop { - match exp.clone() { + match exp { Exp::Sym(key) => return env_get(&key, env), Exp::Bool(_) => return Ok(exp.clone()), Exp::Num(_) => return Ok(exp.clone()), From 078222ecd4ef761b853b80493a1297d8ca8f4756 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 23 Oct 2022 01:18:51 +0200 Subject: [PATCH 12/16] Reorder matches --- src/usr/lisp/eval.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index 8b86fab82..e3755f3b3 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -225,13 +225,6 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { 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 == "lambda" || s == "function" || s == "fun" || s == "fn" => { - ensure_length_eq!(args, 2); - return Ok(Exp::Lambda(Box::new(Lambda { - params: args[0].clone(), - body: args[1].clone(), - }))) - } Exp::Sym(s) if s == "if" => { ensure_length_gt!(args, 1); if eval(&args[0], env)? == Exp::Bool(true) { // consequent @@ -243,17 +236,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" => { + ensure_length_eq!(args, 2); + return Ok(Exp::Lambda(Box::new(Lambda { + params: args[0].clone(), + body: args[1].clone(), + }))) + } _ => { match eval(&list[0], env)? { - Exp::Primitive(f) => { - return f(&eval_args(args, env)?) - }, Exp::Lambda(f) => { env_tmp = lambda_env(&f.params, args, env)?; exp_tmp = f.body.clone(); env = &mut env_tmp; exp = &exp_tmp; }, + Exp::Primitive(f) => { + return f(&eval_args(args, env)?) + }, _ => return Err(Err::Reason("First form must be a function".to_string())), } } From ef780c21b3f1d6eb68da3960aa92f4f312859121 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 23 Oct 2022 01:43:57 +0200 Subject: [PATCH 13/16] Remove another clone --- src/usr/lisp/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index e3755f3b3..0ff842995 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -247,7 +247,7 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { match eval(&list[0], env)? { Exp::Lambda(f) => { env_tmp = lambda_env(&f.params, args, env)?; - exp_tmp = f.body.clone(); + exp_tmp = f.body; env = &mut env_tmp; exp = &exp_tmp; }, From a38d54b9a3d118663612896d6544660e41393ee1 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 23 Oct 2022 01:49:25 +0200 Subject: [PATCH 14/16] Run clippy --- src/usr/lisp/env.rs | 2 +- src/usr/lisp/eval.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/usr/lisp/env.rs b/src/usr/lisp/env.rs index ef5b56cdf..6451a48a0 100644 --- a/src/usr/lisp/env.rs +++ b/src/usr/lisp/env.rs @@ -330,7 +330,7 @@ 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(¶ms)?; + 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()))); diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index 0ff842995..1ec0aa601 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -197,7 +197,7 @@ pub fn eval(exp: &Exp, env: &mut Rc>) -> Result { let mut exp_tmp; loop { match exp { - Exp::Sym(key) => return env_get(&key, env), + Exp::Sym(key) => return env_get(key, env), Exp::Bool(_) => return Ok(exp.clone()), Exp::Num(_) => return Ok(exp.clone()), Exp::Str(_) => return Ok(exp.clone()), From cf21e0722c50c5ebd3ff003fb96a05b3f47ebd44 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Mon, 24 Oct 2022 08:27:22 +0200 Subject: [PATCH 15/16] Remove to_vec --- src/usr/lisp/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index 1ec0aa601..b518fe603 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -61,7 +61,7 @@ fn eval_cons_args(args: &[Exp], env: &mut Rc>) -> Result match eval(&args[1], env)? { Exp::List(mut list) => { list.insert(0, eval(&args[0], env)?); - Ok(Exp::List(list.to_vec())) + Ok(Exp::List(list)) }, _ => Err(Err::Reason("Expected list form".to_string())), } From 511763bfab62fb607196f21a49f096d23fe5fffa Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Mon, 24 Oct 2022 08:33:29 +0200 Subject: [PATCH 16/16] Add comments --- src/usr/lisp/eval.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/usr/lisp/eval.rs b/src/usr/lisp/eval.rs index b518fe603..aace6b11b 100644 --- a/src/usr/lisp/eval.rs +++ b/src/usr/lisp/eval.rs @@ -67,6 +67,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 { @@ -130,6 +131,7 @@ 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);