aboutsummaryrefslogtreecommitdiff
path: root/src/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lisp')
-rw-r--r--src/lisp/error.rs6
-rw-r--r--src/lisp/eval.rs400
-rw-r--r--src/lisp/expr.rs7
-rw-r--r--src/lisp/prelude.rs57
-rw-r--r--src/lisp/std.lisp22
5 files changed, 234 insertions, 258 deletions
diff --git a/src/lisp/error.rs b/src/lisp/error.rs
index 53681d8..f905e6d 100644
--- a/src/lisp/error.rs
+++ b/src/lisp/error.rs
@@ -1,5 +1,5 @@
1use crate::lisp::{ 1use crate::lisp::{
2 expr::Arity, 2 expr::{Arity, LispExpr},
3 lex::{Span, SpanDisplay}, 3 lex::{Span, SpanDisplay},
4}; 4};
5 5
@@ -98,6 +98,7 @@ pub enum EvalError {
98 TypeMismatch, 98 TypeMismatch,
99 NoFileName, 99 NoFileName,
100 AccessEmptyList, 100 AccessEmptyList,
101 AssertionError { expected: LispExpr, got: LispExpr },
101 ScriptLoadError(io::Error), 102 ScriptLoadError(io::Error),
102 CustomInternal(&'static str), 103 CustomInternal(&'static str),
103 Custom(String), 104 Custom(String),
@@ -124,6 +125,9 @@ impl fmt::Display for EvalError {
124 Self::DivByZero => write!(f, "attempt to divide by zero"), 125 Self::DivByZero => write!(f, "attempt to divide by zero"),
125 Self::NoFileName => write!(f, "no file name specified"), 126 Self::NoFileName => write!(f, "no file name specified"),
126 Self::AccessEmptyList => write!(f, "attempted to access empty list"), 127 Self::AccessEmptyList => write!(f, "attempted to access empty list"),
128 Self::AssertionError { expected, got } => {
129 write!(f, "assertion error: expected `{}` got `{}`", expected, got)
130 }
127 Self::ScriptLoadError(s) => write!(f, "error while loading script: {}", s), 131 Self::ScriptLoadError(s) => write!(f, "error while loading script: {}", s),
128 Self::CustomInternal(s) => write!(f, "{}", s), 132 Self::CustomInternal(s) => write!(f, "{}", s),
129 Self::Custom(s) => write!(f, "error: {}", s), 133 Self::Custom(s) => write!(f, "error: {}", s),
diff --git a/src/lisp/eval.rs b/src/lisp/eval.rs
index 44540c0..2e46251 100644
--- a/src/lisp/eval.rs
+++ b/src/lisp/eval.rs
@@ -3,7 +3,6 @@ use crate::{
3 lisp::{ 3 lisp::{
4 error::{EvalError, LispError}, 4 error::{EvalError, LispError},
5 expr::{Arity, Ident, LispExpr, LispFunction}, 5 expr::{Arity, Ident, LispExpr, LispFunction},
6 number::LispNumber,
7 Environment, 6 Environment,
8 }, 7 },
9 type_match, 8 type_match,
@@ -13,155 +12,208 @@ use std::convert::TryInto;
13 12
14use log::{error, info}; 13use log::{error, info};
15 14
16pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result<LispExpr, LispError> { 15pub type Context = Vec<String>;
17 match expr { 16
18 LispExpr::Unit => Ok(expr.clone()), 17pub struct Evaluator<'ctx, 'file, 'global> {
19 LispExpr::StringLit(_) => Ok(expr.clone()), 18 pub app: &'global mut AppState<'ctx, 'file>,
20 LispExpr::Char(_) => Ok(expr.clone()), 19 pub context: Context,
21 LispExpr::Number(_) => Ok(expr.clone()), 20}
22 LispExpr::BoolLit(_) => Ok(expr.clone()), 21
23 LispExpr::Ident(ref id) => lookup_extended(&app.lisp_env, id), 22impl<'ctx, 'file, 'global> Evaluator<'ctx, 'file, 'global>
24 LispExpr::Quote(item, _) => match item.as_ref() { 23where
25 i @ LispExpr::Unit 24 'ctx: 'global,
26 | i @ LispExpr::StringLit(_) 25 'file: 'global,
27 | i @ LispExpr::Char(_) 26{
28 | i @ LispExpr::Number(_) 27 pub fn eval(&mut self, expr: &LispExpr) -> Result<LispExpr, LispError> {
29 | i @ LispExpr::BoolLit(_) => Ok(i.clone()), 28 match expr {
30 _ => Ok(*item.clone()), 29 LispExpr::Unit => Ok(expr.clone()),
31 }, 30 LispExpr::StringLit(_) => Ok(expr.clone()),
32 LispExpr::List(li) => { 31 LispExpr::Char(_) => Ok(expr.clone()),
33 let func_expr = &li[0]; 32 LispExpr::Number(_) => Ok(expr.clone()),
34 match func_expr { 33 LispExpr::BoolLit(_) => Ok(expr.clone()),
35 LispExpr::Ident(s) => match s.as_ref() { 34 LispExpr::Ident(ref id) => lookup(&self.app.lisp_env, id),
36 "define" => define_var(&li[1..], app), 35 LispExpr::Quote(item, _) => match item.as_ref() {
37 "set!" => set_var(&li[1..], app), 36 i @ LispExpr::Unit
38 "lambda" => create_lambda(&li[1..]), 37 | i @ LispExpr::StringLit(_)
39 "if" => eval_if(&li[1..], app), 38 | i @ LispExpr::Char(_)
40 "quote" => eval_quote(&li[1..]), 39 | i @ LispExpr::Number(_)
41 _ => { 40 | i @ LispExpr::BoolLit(_) => Ok(i.clone()),
42 let mut new_ls = vec![eval(&func_expr, app)?]; 41 _ => Ok(*item.clone()),
43 new_ls.extend(li[1..].to_vec()); 42 },
44 eval(&(LispExpr::List(new_ls)), app) 43 LispExpr::List(li) => {
45 } 44 let func_expr = &li[0];
46 }, 45 match func_expr {
47 LispExpr::PrimitiveFunc(f) => { 46 LispExpr::Ident(s) => match s.as_ref() {
48 let mut args = Vec::new(); 47 "define" => self.define_var(&li[1..]),
49 for item in li[1..].iter() { 48 "set!" => self.set_var(&li[1..]),
50 args.push(eval(item, app)?); 49 "lambda" => create_lambda(&li[1..]),
51 } 50 "if" => self.eval_if(&li[1..]),
52 f.call(&args, app) 51 "quote" => eval_quote(&li[1..]),
53 } 52 _ => {
54 LispExpr::Function(f) => { 53 let mut new_ls = vec![self.eval(&func_expr)?];
55 let mut args = Vec::new(); 54 new_ls.extend(li[1..].to_vec());
56 for item in li[1..].iter() { 55 self.eval(&(LispExpr::List(new_ls)))
57 let i = eval(item, app)?; 56 }
58 args.push(i); 57 },
58 LispExpr::PrimitiveFunc(f) => {
59 let mut args = Vec::new();
60 // context.push(f.name.to_string());
61 for item in li[1..].iter() {
62 args.push(self.eval(item)?);
63 }
64 f.call(&args, &mut self.app)
59 } 65 }
60 if f.params.len() != args.len() { 66 LispExpr::Function(f) => {
61 info!("too many or too little number of args"); 67 let mut args = Vec::new();
62 Err(EvalError::ArgumentCount(Arity::Exact(f.params.len())).into()) 68 for item in li[1..].iter() {
63 } else { 69 let i = self.eval(item)?;
64 let nested_env: Environment = 70 args.push(i);
65 f.params.clone().into_iter().zip(args).collect(); 71 }
66 app.lisp_env.push(nested_env); 72 if f.params.len() != args.len() {
67 let result = if f.body.is_empty() { 73 info!("too many or too little number of args");
68 Ok(LispExpr::Unit) 74 Err(EvalError::ArgumentCount(Arity::Exact(f.params.len())).into())
69 } else { 75 } else {
70 eval(&LispExpr::List(f.body.clone()), app) 76 let nested_env: Environment =
71 }; 77 f.params.clone().into_iter().zip(args).collect();
72 app.lisp_env.pop(); 78 self.app.lisp_env.push(nested_env);
73 return result; 79 let result = if f.body.is_empty() {
80 Ok(LispExpr::Unit)
81 } else {
82 self.eval(&LispExpr::List(f.body.clone()))
83 };
84 self.app.lisp_env.pop();
85 return result;
86 }
74 } 87 }
88 LispExpr::List(_) => {
89 info!("list as funciton");
90 let func_expr = self.eval(&func_expr)?;
91 let mut new_ls = vec![func_expr];
92 new_ls.extend(li[1..].to_vec());
93 self.eval(&(LispExpr::List(new_ls)))
94 }
95 _ => Err(EvalError::BadForm.into()),
75 } 96 }
76 LispExpr::List(_) => {
77 info!("list as funciton");
78 let func_expr = eval(&func_expr, app)?;
79 let mut new_ls = vec![func_expr];
80 new_ls.extend(li[1..].to_vec());
81 eval(&(LispExpr::List(new_ls)), app)
82 }
83 _ => Err(EvalError::BadForm.into()),
84 } 97 }
98 _ => Err(EvalError::BadForm.into()),
85 } 99 }
86 _ => Err(EvalError::BadForm.into()),
87 } 100 }
88}
89 101
90pub fn define_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { 102 pub fn define_var(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> {
91 info!("defining"); 103 let arity = Arity::Exact(2);
92 let arity = Arity::Exact(2); 104 if !arity.is_valid(args) {
93 if !arity.is_valid(args) { 105 return Err(arity.to_error());
94 return Err(arity.to_error());
95 }
96 match args {
97 [LispExpr::Ident(id), expr] => {
98 let value = eval(&expr, app)?;
99 let local_env = app.lisp_env.last_mut();
100 if let Some(env) = local_env {
101 env.insert(id.into(), value);
102 } else {
103 error!("Unable to create global definition");
104 return Err(EvalError::BadForm.into());
105 }
106 return Ok(LispExpr::Unit);
107 } 106 }
108 [LispExpr::List(shorthand), LispExpr::List(body)] => { 107 match args {
109 // (define (func arg) <body>) shorthand 108 [LispExpr::Ident(id), expr] => {
109 let value = self.eval(&expr)?;
110 let local_env = &mut self.app.lisp_env.last_mut();
111 if let Some(env) = local_env {
112 env.insert(id.into(), value);
113 } else {
114 error!("Unable to create global definition");
115 return Err(EvalError::BadForm.into());
116 }
117 return Ok(LispExpr::Unit);
118 }
119 [LispExpr::List(shorthand), LispExpr::List(body)] => {
120 // (define (func arg) <body>) shorthand
110 121
111 let id = shorthand[0].unwrap_ident(); 122 let id = shorthand[0].unwrap_ident();
112 let params = if shorthand.len() > 1 { 123 let params = if shorthand.len() > 1 {
113 &shorthand[1..] 124 &shorthand[1..]
114 } else { 125 } else {
115 &[] 126 &[]
127 }
128 .to_vec()
129 .into_iter()
130 .map(|arg| arg.try_into())
131 .collect::<Result<Vec<Ident>, LispError>>()?;
132 let value = LispExpr::Function(LispFunction {
133 params,
134 body: body.to_vec(),
135 });
136
137 let local_env = &mut self.app.lisp_env.last_mut();
138 if let Some(env) = local_env {
139 env.insert(id.into(), value);
140 } else {
141 error!("Unable to create global definition");
142 return Err(EvalError::BadForm.into());
143 }
144 return Ok(LispExpr::Unit);
145 }
146 _ => {
147 error!("Invalid usage of `define`");
148 Err(EvalError::BadForm.into())
116 } 149 }
117 .to_vec() 150 }
118 .into_iter() 151 }
119 .map(|arg| arg.try_into())
120 .collect::<Result<Vec<Ident>, LispError>>()?;
121 let value = LispExpr::Function(LispFunction {
122 params,
123 body: body.to_vec(),
124 });
125 152
126 let local_env = app.lisp_env.last_mut(); 153 pub fn set_var(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> {
127 if let Some(env) = local_env { 154 let arity = Arity::Exact(2);
128 info!("creating function {}", id); 155 if !arity.is_valid(args) {
129 env.insert(id.into(), value); 156 return Err(arity.to_error());
130 } else { 157 }
131 error!("Unable to create global definition"); 158 match args {
159 [LispExpr::Ident(id), expr] => {
160 let value = self.eval(&expr)?;
161 let local_env = self.app.lisp_env.last_mut();
162 if let Some(env) = local_env {
163 return env
164 .insert(id.into(), value)
165 .ok_or(EvalError::UnboundVariable(id.into()).into());
166 } else {
167 error!("Unable to set in global env!");
168 return Err(EvalError::BadForm.into());
169 }
170 }
171 _ => {
172 error!("Invalid usage of `set!`");
132 return Err(EvalError::BadForm.into()); 173 return Err(EvalError::BadForm.into());
133 } 174 }
134 return Ok(LispExpr::Unit);
135 } 175 }
136 _ => { 176 }
137 error!("Invalid usage of `define`"); 177
138 Err(EvalError::BadForm.into()) 178 pub fn eval_if(&mut self, args: &[LispExpr]) -> Result<LispExpr, LispError> {
179 let arity = Arity::Exact(3);
180 if !arity.is_valid(args) {
181 return Err(arity.to_error());
182 } else {
183 match args {
184 [predicate, then, else_] => {
185 let predicate = self.eval(&predicate)?;
186 if matches!(predicate, LispExpr::BoolLit(false)) {
187 return self.eval(&else_);
188 } else {
189 return self.eval(&then);
190 }
191 }
192 _ => {
193 panic!("panicked at `if` expression")
194 }
195 }
139 } 196 }
140 } 197 }
141} 198}
142 199
143pub fn set_var(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { 200pub fn eval_quote(args: &[LispExpr]) -> Result<LispExpr, LispError> {
144 let arity = Arity::Exact(2); 201 let arity = Arity::Exact(1);
145 if !arity.is_valid(args) { 202 if !arity.is_valid(args) {
146 return Err(arity.to_error()); 203 return Err(arity.to_error());
147 } 204 } else {
148 match args { 205 match &args[0] {
149 [LispExpr::Ident(id), expr] => { 206 LispExpr::Quote(item, depth) => Ok(LispExpr::Quote(item.clone(), depth + 1)),
150 let value = eval(&expr, app)?; 207 i @ LispExpr::Unit
151 let local_env = app.lisp_env.last_mut(); 208 | i @ LispExpr::StringLit(_)
152 if let Some(env) = local_env { 209 | i @ LispExpr::Char(_)
153 return env 210 | i @ LispExpr::Number(_)
154 .insert(id.into(), value) 211 | i @ LispExpr::BoolLit(_) => Ok(i.clone()),
155 .ok_or(EvalError::UnboundVariable(id.into()).into()); 212 _ => {
156 } else { 213 let quoted_expr = Box::new(args[0].clone());
157 error!("Unable to set in global env!"); 214 Ok(LispExpr::Quote(quoted_expr, 1))
158 return Err(EvalError::BadForm.into());
159 } 215 }
160 } 216 }
161 _ => {
162 error!("Invalid usage of `set!`");
163 return Err(EvalError::BadForm.into());
164 }
165 } 217 }
166} 218}
167 219
@@ -170,7 +222,6 @@ pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> {
170 if !arity.is_valid(cdr) { 222 if !arity.is_valid(cdr) {
171 return Err(arity.to_error()); 223 return Err(arity.to_error());
172 } 224 }
173 info!("creating lambda");
174 match cdr { 225 match cdr {
175 [LispExpr::List(params), LispExpr::List(body)] if type_match!(params, (..) => LispExpr::Ident(_)) => 226 [LispExpr::List(params), LispExpr::List(body)] if type_match!(params, (..) => LispExpr::Ident(_)) =>
176 { 227 {
@@ -189,48 +240,7 @@ pub fn create_lambda(cdr: &[LispExpr]) -> Result<LispExpr, LispError> {
189 } 240 }
190} 241}
191 242
192pub fn eval_if(args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { 243pub fn lookup(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> {
193 let arity = Arity::Exact(3);
194 if !arity.is_valid(args) {
195 return Err(arity.to_error());
196 } else {
197 match args {
198 [predicate, then, else_] => {
199 let predicate = eval(&predicate, app)?;
200 if matches!(predicate, LispExpr::BoolLit(false)) {
201 return eval(&else_, app);
202 } else {
203 return eval(&then, app);
204 }
205 }
206 _ => {
207 panic!("panicked at `if` expression")
208 }
209 }
210 }
211}
212
213pub fn eval_quote(args: &[LispExpr]) -> Result<LispExpr, LispError> {
214 let arity = Arity::Exact(1);
215 if !arity.is_valid(args) {
216 return Err(arity.to_error());
217 } else {
218 match &args[0] {
219 LispExpr::Quote(item, depth) => Ok(LispExpr::Quote(item.clone(), depth + 1)),
220 i @ LispExpr::Unit
221 | i @ LispExpr::StringLit(_)
222 | i @ LispExpr::Char(_)
223 | i @ LispExpr::Number(_)
224 | i @ LispExpr::BoolLit(_) => Ok(i.clone()),
225 _ => {
226 let quoted_expr = Box::new(args[0].clone());
227 Ok(LispExpr::Quote(quoted_expr, 1))
228 }
229 }
230 }
231}
232
233pub fn lookup_extended(env_list: &[Environment], key: &str) -> Result<LispExpr, LispError> {
234 if env_list.is_empty() { 244 if env_list.is_empty() {
235 return Err(EvalError::UnboundVariable(key.into()).into()); 245 return Err(EvalError::UnboundVariable(key.into()).into());
236 } else { 246 } else {
@@ -238,55 +248,7 @@ pub fn lookup_extended(env_list: &[Environment], key: &str) -> Result<LispExpr,
238 if let Some(val) = local_env.get(key) { 248 if let Some(val) = local_env.get(key) {
239 return Ok(val.clone()); 249 return Ok(val.clone());
240 } else { 250 } else {
241 return lookup_extended(&env_list[..env_list.len() - 1], key); 251 return lookup(&env_list[..env_list.len() - 1], key);
242 } 252 }
243 } 253 }
244} 254}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 use crate::lisp::{expr::LispExpr, lex::Lexer, number::LispNumber, parse::Parser};
251
252 fn run(code: &str, app: &mut AppState) -> LispExpr {
253 let mut parser = Parser::new(Lexer::new(code, 0));
254 eval(&parser.parse_single_expr().unwrap(), app).unwrap()
255 }
256
257 #[test]
258 fn eval_all() {
259 let sdl_context = sdl2::init().unwrap();
260 let ttf_context = sdl2::ttf::init().unwrap();
261 let mut app = AppState::init(100, 100, &sdl_context, &ttf_context, None, None);
262 eval_arithmetic(&mut app);
263 eval_logical(&mut app);
264 }
265
266 fn eval_arithmetic(app: &mut AppState) {
267 assert_eq!(
268 run("(+ 1 2 3)", app),
269 LispExpr::Number(LispNumber::Integer(6))
270 );
271 assert_eq!(
272 run("(+ 1.1 2.2 3.3)", app),
273 LispExpr::Number(LispNumber::Float(6.6))
274 );
275 assert_eq!(
276 run("(* 1 2 3 4 5)", app),
277 LispExpr::Number(LispNumber::Integer(120))
278 );
279 assert_eq!(run("(< 1 2)", app), LispExpr::BoolLit(true));
280 assert_eq!(run("(> 6 5 4 3 2 1)", app), LispExpr::BoolLit(true));
281 assert_eq!(run("(< 1 2 3 4 5 6)", app), LispExpr::BoolLit(true));
282 assert_eq!(run("(>= 5 5 4 3 2 1)", app), LispExpr::BoolLit(true));
283 assert_eq!(run("(<= 2 2 3 4 5 6)", app), LispExpr::BoolLit(true));
284 }
285
286 fn eval_logical(app: &mut AppState) {
287 assert_eq!(run("(and #t #t)", app), LispExpr::BoolLit(true));
288 assert_eq!(run("(or #f #t)", app), LispExpr::BoolLit(true));
289 assert_eq!(run("(not #t)", app), LispExpr::BoolLit(false));
290 assert_eq!(run("(not #f)", app), run("(not (not #t))", app));
291 }
292}
diff --git a/src/lisp/expr.rs b/src/lisp/expr.rs
index 9f2dc8d..1f3e0fb 100644
--- a/src/lisp/expr.rs
+++ b/src/lisp/expr.rs
@@ -3,7 +3,7 @@ use std::{cmp::PartialEq, convert::TryFrom, fmt};
3use crate::app::AppState; 3use crate::app::AppState;
4use crate::lisp::{ 4use crate::lisp::{
5 error::{EvalError, LispError}, 5 error::{EvalError, LispError},
6 eval::lookup_extended, 6 eval::{lookup, Evaluator},
7 number::LispNumber, 7 number::LispNumber,
8 EnvList, 8 EnvList,
9}; 9};
@@ -36,6 +36,7 @@ impl Arity {
36pub struct PrimitiveFunc { 36pub struct PrimitiveFunc {
37 pub arity: Arity, // minimim arity 37 pub arity: Arity, // minimim arity
38 pub closure: fn(&[LispExpr], &mut AppState) -> Result<LispExpr, LispError>, 38 pub closure: fn(&[LispExpr], &mut AppState) -> Result<LispExpr, LispError>,
39 pub name: &'static str,
39} 40}
40 41
41impl PrimitiveFunc { 42impl PrimitiveFunc {
@@ -123,8 +124,8 @@ impl LispExpr {
123 (LispExpr::Char(s), LispExpr::Char(o)) => Ok(s == o), 124 (LispExpr::Char(s), LispExpr::Char(o)) => Ok(s == o),
124 (LispExpr::BoolLit(s), LispExpr::BoolLit(o)) => Ok(s == o), 125 (LispExpr::BoolLit(s), LispExpr::BoolLit(o)) => Ok(s == o),
125 (LispExpr::Ident(s), LispExpr::Ident(o)) => { 126 (LispExpr::Ident(s), LispExpr::Ident(o)) => {
126 let s = lookup_extended(envs, s)?; 127 let s = lookup(envs, s)?;
127 let o = lookup_extended(envs, o)?; 128 let o = lookup(envs, o)?;
128 s.compare(&o, envs) 129 s.compare(&o, envs)
129 } 130 }
130 (LispExpr::PrimitiveFunc(s), LispExpr::PrimitiveFunc(o)) => { 131 (LispExpr::PrimitiveFunc(s), LispExpr::PrimitiveFunc(o)) => {
diff --git a/src/lisp/prelude.rs b/src/lisp/prelude.rs
index dffd9f4..27e7ad2 100644
--- a/src/lisp/prelude.rs
+++ b/src/lisp/prelude.rs
@@ -2,7 +2,7 @@ use crate::{
2 brush::Brush, 2 brush::Brush,
3 lisp::{ 3 lisp::{
4 error::{EvalError, LispError}, 4 error::{EvalError, LispError},
5 eval::eval, 5 eval::Evaluator,
6 expr::{Arity, LispExpr}, 6 expr::{Arity, LispExpr},
7 number::LispNumber, 7 number::LispNumber,
8 Environment, 8 Environment,
@@ -21,6 +21,7 @@ macro_rules! primitive {
21 let val = crate::lisp::expr::LispExpr::PrimitiveFunc(crate::lisp::expr::PrimitiveFunc { 21 let val = crate::lisp::expr::LispExpr::PrimitiveFunc(crate::lisp::expr::PrimitiveFunc {
22 arity: $arity, 22 arity: $arity,
23 closure: $closure, 23 closure: $closure,
24 name: $name,
24 }); 25 });
25 let _ = $env.insert($name.to_string(), val); 26 let _ = $env.insert($name.to_string(), val);
26 }; 27 };
@@ -241,41 +242,15 @@ pub fn new_env() -> Result<Environment, LispError> {
241 return Ok(LispExpr::Unit); 242 return Ok(LispExpr::Unit);
242 }); 243 });
243 244
244 primitive!(env, Arity::Exact(2), "map", |args, app| { 245 primitive!(env, Arity::Exact(2), "cons", |args, _| {
245 let mut apply_map = 246 if type_match!(args, 1 => LispExpr::Unit) {
246 |func: &LispExpr, ls: &Vec<LispExpr>| -> Result<Vec<LispExpr>, LispError> { 247 return Ok(LispExpr::List(vec![args[0].clone()]));
247 ls.into_iter() 248 } else if !type_match!(args, 1 => LispExpr::List(_)) {
248 .map(|arg| eval(&LispExpr::List(vec![func.clone(), arg.clone()]), app)) 249 return Ok(LispExpr::List(vec![args[0].clone(), args[1].clone()]));
249 .collect()
250 };
251 if matches!(&args[0], LispExpr::Function(_) | LispExpr::PrimitiveFunc(_)) {
252 match &args[1] {
253 LispExpr::List(ls) => return Ok(LispExpr::List(apply_map(&args[0], ls)?)),
254 _ => return Err(EvalError::TypeMismatch.into()),
255 }
256 } else {
257 return Err(EvalError::TypeMismatch.into());
258 }
259 });
260
261 primitive!(env, Arity::Exact(2), "filter", |args, app| {
262 let mut apply_filter =
263 |func: &LispExpr, ls: &Vec<LispExpr>| -> Result<Vec<LispExpr>, LispError> {
264 let mut result = vec![];
265 for arg in ls.into_iter() {
266 if eval(&LispExpr::List(vec![func.clone(), arg.clone()]), app)?.cast_bool() {
267 result.push(arg.clone())
268 }
269 }
270 Ok(result)
271 };
272 if matches!(&args[0], LispExpr::Function(_) | LispExpr::PrimitiveFunc(_)) {
273 match &args[1] {
274 LispExpr::List(ls) => return Ok(LispExpr::List(apply_filter(&args[0], ls)?)),
275 _ => return Err(EvalError::TypeMismatch.into()),
276 }
277 } else { 250 } else {
278 return Err(EvalError::TypeMismatch.into()); 251 let mut rest = args[1].unwrap_list();
252 rest.insert(0, args[0].clone());
253 return Ok(LispExpr::List(rest));
279 } 254 }
280 }); 255 });
281 256
@@ -332,5 +307,17 @@ pub fn new_env() -> Result<Environment, LispError> {
332 } 307 }
333 }); 308 });
334 309
310 primitive!(env, Arity::Exact(2), "assert-eq", |args, app| {
311 if args[0].compare(&args[1], &app.lisp_env)? {
312 return Ok(LispExpr::Unit);
313 } else {
314 return Err(EvalError::AssertionError {
315 expected: args[0].clone(),
316 got: args[1].clone(),
317 }
318 .into());
319 }
320 });
321
335 Ok(env) 322 Ok(env)
336} 323}
diff --git a/src/lisp/std.lisp b/src/lisp/std.lisp
index c723a13..8350482 100644
--- a/src/lisp/std.lisp
+++ b/src/lisp/std.lisp
@@ -22,5 +22,27 @@
22 accumulator 22 accumulator
23 (cdr ls)))) 23 (cdr ls))))
24 24
25(define (map func ls)
26 (if (null? ls)
27 '()
28 (cons (func (car ls))
29 (map func (cdr ls)))))
30
31(define (filter pred ls)
32 (if (null? ls)
33 '()
34 (if (pred (car ls))
35 (cons (car ls) (filter pred (cdr ls)))
36 (filter pred (cdr ls)))))
37
38(define (member? item ls)
39 (if (null? ls)
40 #f
41 (or (eq? item (car ls))
42 (member? item (cdr ls)))))
43
44(define (assert expr)
45 (assert-eq #t expr))
46
25(define (sum ls) (fold 0 + ls)) 47(define (sum ls) (fold 0 + ls))
26(define (product ls) (fold 1 * ls)) 48(define (product ls) (fold 1 * ls))