diff options
Diffstat (limited to 'src/lisp')
-rw-r--r-- | src/lisp/eval.rs | 48 | ||||
-rw-r--r-- | src/lisp/expr.rs | 54 | ||||
-rw-r--r-- | src/lisp/parse.rs | 53 |
3 files changed, 117 insertions, 38 deletions
diff --git a/src/lisp/eval.rs b/src/lisp/eval.rs index f7f918a..f49efb9 100644 --- a/src/lisp/eval.rs +++ b/src/lisp/eval.rs | |||
@@ -222,3 +222,51 @@ pub fn unwrap_ident(i: LispExpr) -> String { | |||
222 | _ => panic!("unwrap_ident expected string"), | 222 | _ => panic!("unwrap_ident expected string"), |
223 | } | 223 | } |
224 | } | 224 | } |
225 | |||
226 | #[cfg(test)] | ||
227 | mod tests { | ||
228 | use super::*; | ||
229 | |||
230 | use crate::lisp::{expr::LispExpr, lex::Lexer, number::LispNumber, parse::Parser}; | ||
231 | |||
232 | fn run(code: &str, app: &mut AppState) -> LispExpr { | ||
233 | let mut parser = Parser::new(Lexer::new(code, 0)); | ||
234 | eval(&parser.parse_single_expr().unwrap(), app).unwrap() | ||
235 | } | ||
236 | |||
237 | #[test] | ||
238 | fn eval_all() { | ||
239 | let sdl_context = sdl2::init().unwrap(); | ||
240 | let ttf_context = sdl2::ttf::init().unwrap(); | ||
241 | let mut app = AppState::init(100, 100, &sdl_context, &ttf_context, None, None); | ||
242 | eval_arithmetic(&mut app); | ||
243 | eval_logical(&mut app); | ||
244 | } | ||
245 | |||
246 | fn eval_arithmetic(app: &mut AppState) { | ||
247 | assert_eq!( | ||
248 | run("(+ 1 2 3)", app), | ||
249 | LispExpr::Number(LispNumber::Integer(6)) | ||
250 | ); | ||
251 | assert_eq!( | ||
252 | run("(+ 1.1 2.2 3.3)", app), | ||
253 | LispExpr::Number(LispNumber::Float(6.6)) | ||
254 | ); | ||
255 | assert_eq!( | ||
256 | run("(* 1 2 3 4 5)", app), | ||
257 | LispExpr::Number(LispNumber::Integer(120)) | ||
258 | ); | ||
259 | assert_eq!(run("(< 1 2)", app), LispExpr::BoolLit(true)); | ||
260 | assert_eq!(run("(> 6 5 4 3 2 1)", app), LispExpr::BoolLit(true)); | ||
261 | assert_eq!(run("(< 1 2 3 4 5 6)", app), LispExpr::BoolLit(true)); | ||
262 | assert_eq!(run("(>= 5 5 4 3 2 1)", app), LispExpr::BoolLit(true)); | ||
263 | assert_eq!(run("(<= 2 2 3 4 5 6)", app), LispExpr::BoolLit(true)); | ||
264 | } | ||
265 | |||
266 | fn eval_logical(app: &mut AppState) { | ||
267 | assert_eq!(run("(and #t #t)", app), LispExpr::BoolLit(true)); | ||
268 | assert_eq!(run("(or #f #t)", app), LispExpr::BoolLit(true)); | ||
269 | assert_eq!(run("(not #t)", app), LispExpr::BoolLit(false)); | ||
270 | assert_eq!(run("(not #f)", app), run("(not (not #t))", app)); | ||
271 | } | ||
272 | } | ||
diff --git a/src/lisp/expr.rs b/src/lisp/expr.rs index 8fd794e..059113b 100644 --- a/src/lisp/expr.rs +++ b/src/lisp/expr.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use std::{convert::TryFrom, fmt}; | 1 | use std::{cmp::PartialEq, convert::TryFrom, fmt}; |
2 | 2 | ||
3 | use crate::app::AppState; | 3 | use crate::app::AppState; |
4 | use crate::lisp::{ | 4 | use crate::lisp::{ |
@@ -177,6 +177,47 @@ impl fmt::Display for LispExpr { | |||
177 | } | 177 | } |
178 | } | 178 | } |
179 | 179 | ||
180 | impl fmt::Debug for LispExpr { | ||
181 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
182 | match self { | ||
183 | LispExpr::Unit => f.debug_tuple("Unit").finish(), | ||
184 | LispExpr::Number(n) => write!(f, "Number({:?})", n), | ||
185 | LispExpr::List(l) => f.debug_list().entries(l.iter()).finish(), | ||
186 | LispExpr::StringLit(s) => write!(f, "String({:?})", s), | ||
187 | LispExpr::Char(c) => write!(f, "Char({:?})", c), | ||
188 | LispExpr::BoolLit(b) => write!(f, "Bool({:?})", b), | ||
189 | LispExpr::Ident(s) => write!(f, "Ident({})", s), | ||
190 | LispExpr::PrimitiveFunc(_) => write!(f, "Primitive"), | ||
191 | LispExpr::Function(func) => write!(f, "<#lambda> {}", func.params.join(" ")), | ||
192 | LispExpr::Quasiquote(val, depth) => write!(f, "{}{}", "`".repeat(*depth as usize), val), | ||
193 | LispExpr::Comma(val, depth) => write!(f, "{}{}", ",".repeat(*depth as usize), val), | ||
194 | LispExpr::CommaAt(val, depth) => write!(f, "{}@{}", ",".repeat(*depth as usize), val), | ||
195 | LispExpr::Quote(val, depth) => write!(f, "{}{}", "'".repeat(*depth as usize), val), | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | |||
200 | impl PartialEq for LispExpr { | ||
201 | fn eq(&self, other: &Self) -> bool { | ||
202 | match (self, other) { | ||
203 | (LispExpr::Unit, LispExpr::Unit) => true, | ||
204 | (LispExpr::Number(s), LispExpr::Number(o)) => s == o, | ||
205 | (LispExpr::List(s), LispExpr::List(o)) => s.iter().zip(o).all(|(a, b)| a == b), | ||
206 | (LispExpr::StringLit(s), LispExpr::StringLit(o)) => s == o, | ||
207 | (LispExpr::Char(s), LispExpr::Char(o)) => s == o, | ||
208 | (LispExpr::BoolLit(s), LispExpr::BoolLit(o)) => s == o, | ||
209 | (LispExpr::Ident(s), LispExpr::Ident(o)) => s == o, | ||
210 | (LispExpr::PrimitiveFunc(_), LispExpr::PrimitiveFunc(_)) => false, | ||
211 | (LispExpr::Function(_), LispExpr::Function(_)) => false, | ||
212 | (LispExpr::Quasiquote(s, sd), LispExpr::Quasiquote(o, od)) => (s, sd) == (o, od), | ||
213 | (LispExpr::Comma(s, sd), LispExpr::Comma(o, od)) => (s, sd) == (o, od), | ||
214 | (LispExpr::CommaAt(s, sd), LispExpr::CommaAt(o, od)) => (s, sd) == (o, od), | ||
215 | (LispExpr::Quote(s, sd), LispExpr::Quote(o, od)) => (s, sd) == (o, od), | ||
216 | _ => false, | ||
217 | } | ||
218 | } | ||
219 | } | ||
220 | |||
180 | impl TryFrom<LispExpr> for LispNumber { | 221 | impl TryFrom<LispExpr> for LispNumber { |
181 | type Error = LispError; | 222 | type Error = LispError; |
182 | fn try_from(value: LispExpr) -> Result<Self, Self::Error> { | 223 | fn try_from(value: LispExpr) -> Result<Self, Self::Error> { |
@@ -197,17 +238,6 @@ impl<'a> TryFrom<&'a LispExpr> for &'a LispNumber { | |||
197 | } | 238 | } |
198 | } | 239 | } |
199 | 240 | ||
200 | //impl TryFrom<LispExpr> for Ident { | ||
201 | // type Error = LispError; | ||
202 | // fn try_from(value: LispExpr) -> Result<Self, Self::Error> { | ||
203 | // match value { | ||
204 | // LispExpr::Ident(i) => Ok(i), | ||
205 | // _ => Err(LispError::Eval(EvalError::TypeMismatch)), | ||
206 | // } | ||
207 | // } | ||
208 | //} | ||
209 | // | ||
210 | // | ||
211 | impl TryFrom<LispExpr> for String { | 241 | impl TryFrom<LispExpr> for String { |
212 | type Error = LispError; | 242 | type Error = LispError; |
213 | fn try_from(value: LispExpr) -> Result<Self, Self::Error> { | 243 | fn try_from(value: LispExpr) -> Result<Self, Self::Error> { |
diff --git a/src/lisp/parse.rs b/src/lisp/parse.rs index 7cca434..6a8de9f 100644 --- a/src/lisp/parse.rs +++ b/src/lisp/parse.rs | |||
@@ -210,32 +210,33 @@ mod tests { | |||
210 | } | 210 | } |
211 | 211 | ||
212 | #[test] | 212 | #[test] |
213 | // fn parse_lisp_expr() { | 213 | fn parse_lisp_expr() { |
214 | // assert_eq!( | 214 | assert_eq!( |
215 | // parse("1.5").unwrap(), | 215 | parse("1.5").unwrap(), |
216 | // LispExpr::Number(LispNumber::Float(1.5)) | 216 | LispExpr::Number(LispNumber::Float(1.5)) |
217 | // ); | 217 | ); |
218 | 218 | ||
219 | // assert_eq!( | 219 | assert_eq!( |
220 | // parse(r#""hello""#).unwrap(), | 220 | parse(r#""hello""#).unwrap(), |
221 | // LispExpr::StringLit(r#""hello""#.into()) | 221 | LispExpr::StringLit("hello".into()) |
222 | // ); | 222 | ); |
223 | 223 | ||
224 | // assert_eq!(parse("foo").unwrap(), LispExpr::Ident("foo".into())); | 224 | assert_eq!(parse("foo").unwrap(), LispExpr::Ident("foo".into())); |
225 | 225 | ||
226 | // let items = (1..=5) | 226 | let items = (1..=5) |
227 | // .map(LispNumber::Integer) | 227 | .map(LispNumber::Integer) |
228 | // .map(LispExpr::Number) | 228 | .map(LispExpr::Number) |
229 | // .collect::<Vec<_>>(); | 229 | .collect::<Vec<_>>(); |
230 | // assert_eq!(parse("(1 2 3 4 5)").unwrap(), LispExpr::List(items)); | 230 | assert_eq!(parse("(1 2 3 4 5)").unwrap(), LispExpr::List(items)); |
231 | 231 | ||
232 | // let foo = LispExpr::Ident("foo".into()); | 232 | let foo = LispExpr::Ident("foo".into()); |
233 | // let bar = LispExpr::Comma(Box::new(LispExpr::Ident("bar".into())), 1); | 233 | let bar = LispExpr::Comma(Box::new(LispExpr::Ident("bar".into())), 1); |
234 | // assert_eq!( | 234 | assert_eq!( |
235 | // parse("`(foo ,bar)").unwrap(), | 235 | parse("`(foo ,bar)").unwrap(), |
236 | // LispExpr::Quasiquote(Box::new(LispExpr::List(vec![foo, bar])), 1) | 236 | LispExpr::Quasiquote(Box::new(LispExpr::List(vec![foo, bar])), 1) |
237 | // ) | 237 | ) |
238 | // } | 238 | } |
239 | |||
239 | #[should_panic] | 240 | #[should_panic] |
240 | #[test] | 241 | #[test] |
241 | fn unbalanced_comma() { | 242 | fn unbalanced_comma() { |