diff --git a/src/bin/demo.rs b/src/bin/demo.rs index 20fc60d..ceb91ec 100644 --- a/src/bin/demo.rs +++ b/src/bin/demo.rs @@ -13,6 +13,8 @@ fn main() { "(pow 2 10)", "(let '((fib . (lambda (n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))))) (fib 10))", "(let '((a . (vec3 1 2 3)) (b . (vec3 4 5 6))) (vec3-dot (vec3-norm (vec3-add a b)) a))", + "(defun do-n-times (f n) (if (= n 0) '() (cons (f) (do-n-times f (- n 1)))))", + "(do-n-times (lambda () (print 'hello)) 5)", ]; let environment = Environment::default(); diff --git a/src/lisp/prelude.rs b/src/lisp/prelude.rs index 1e565cc..3e6e5a7 100644 --- a/src/lisp/prelude.rs +++ b/src/lisp/prelude.rs @@ -94,6 +94,40 @@ pub fn prelude_lambda(_env: &Environment, expr: Expression) -> Result Result { + let [name, args, body]: [Expression; 3] = expr.try_into()?; + let name = match name { + Expression::Symbol(s) => s, + x => return Err(EvalError::NotASymbol(x)), + }; + let mut arg_exprs: Vec = args.try_into()?; + let argument_symbols: Vec = arg_exprs + .iter_mut() + .map(|a| match a.to_owned() { + Expression::Symbol(s) => Ok(s), + x => Err(EvalError::NotASymbol(x)), + }) + .collect::, EvalError>>()?; + + let f = Expression::AnonymousFunction { + argument_symbols, + body: Box::new(body), + }; + env.shared_set(name, f.clone()); + Ok(f) +} + +pub fn prelude_define(env: &Environment, expr: Expression) -> Result { + let [name, value] = expr.try_into()?; + let name = match name { + Expression::Symbol(s) => s, + x => return Err(EvalError::NotASymbol(x)), + }; + let value = eval(env, value)?; + env.shared_set(name, value.clone()); + Ok(value) +} + pub fn prelude_let(env: &Environment, expr: Expression) -> Result { let [bindings, body] = expr.try_into()?; @@ -160,7 +194,7 @@ pub fn prelude_gt(env: &Environment, expr: Expression) -> Result Result { let [a] = expr.try_into()?; - match a { + match eval(env, a)? { Expression::Nil => Ok(Expression::True), _ => Ok(Expression::Nil), } @@ -217,6 +251,8 @@ pub fn mk_prelude(layer: &mut EnvironmentLayer) { layer.set("*".to_string(), Expression::Function(prelude_mul)); layer.set("/".to_string(), Expression::Function(prelude_div)); layer.set("lambda".to_string(), Expression::Function(prelude_lambda)); + layer.set("defun".to_string(), Expression::Function(prelude_defun)); + layer.set("define".to_string(), Expression::Function(prelude_define)); layer.set("if".to_string(), Expression::Function(prelude_if)); layer.set("=".to_string(), Expression::Function(prelude_eq)); layer.set("<".to_string(), Expression::Function(prelude_lt)); diff --git a/src/lisp/vec.rs b/src/lisp/vec.rs index a2ce804..266ada9 100644 --- a/src/lisp/vec.rs +++ b/src/lisp/vec.rs @@ -1,7 +1,5 @@ use std::fmt::Display; -use as_any::AsAny; - use super::{ environment::{Environment, EnvironmentLayer}, eval::{eval, EvalError},