aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lisp/eval.rs48
-rw-r--r--src/lisp/expr.rs54
-rw-r--r--src/lisp/parse.rs53
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)]
227mod 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 @@
1use std::{convert::TryFrom, fmt}; 1use std::{cmp::PartialEq, convert::TryFrom, fmt};
2 2
3use crate::app::AppState; 3use crate::app::AppState;
4use crate::lisp::{ 4use crate::lisp::{
@@ -177,6 +177,47 @@ impl fmt::Display for LispExpr {
177 } 177 }
178} 178}
179 179
180impl 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
200impl 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
180impl TryFrom<LispExpr> for LispNumber { 221impl 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//
211impl TryFrom<LispExpr> for String { 241impl 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() {