From 465c3a1045625d12a73e723651ae9bd9b0a51cb1 Mon Sep 17 00:00:00 2001 From: Kjetil Orbekk Date: Sun, 19 Nov 2023 19:28:42 -0500 Subject: lisp eval --- lisp/src/ast.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++++- lisp/src/eval.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ lisp/src/lib.rs | 2 ++ lisp/src/main.rs | 2 ++ lisp/src/primitives.rs | 1 + 5 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 lisp/src/eval.rs create mode 100644 lisp/src/main.rs create mode 100644 lisp/src/primitives.rs (limited to 'lisp') diff --git a/lisp/src/ast.rs b/lisp/src/ast.rs index 8cac963..929383f 100644 --- a/lisp/src/ast.rs +++ b/lisp/src/ast.rs @@ -1,7 +1,64 @@ -#[derive(Clone, Debug, PartialEq, Eq)] +use std::fmt; + +#[derive(Clone, PartialEq, Eq)] pub enum Val { Atom(String), List(Vec), I64(i64), String(String), } + +impl fmt::Debug for Val { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Val::Atom(v) => write!(f, "{v}"), + Val::List(vs) => { + f.write_str("(")?; + for (i, v) in vs.iter().enumerate() { + if i != 0 { + f.write_str(" ")?; + } + v.fmt(f)?; + } + f.write_str(")")?; + Ok(()) + } + Val::I64(v) => v.fmt(f), + Val::String(s) => s.fmt(f), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn print_string() { + assert_eq!( + format!("{:?}", Val::String("Hello, World!".to_string())), + "\"Hello, World!\"".to_string() + ); + } + #[test] + fn print_atom() { + assert_eq!( + format!("{:?}", Val::Atom("boo-guff".to_string())), + "boo-guff".to_string() + ); + } + #[test] + fn print_i64() { + assert_eq!( + format!("{:?}", Val::I64(1234)), + "1234".to_string() + ); + } + #[test] + fn print_list() { + assert_eq!( + format!("{:?}", Val::List(vec!(Val::Atom("a".to_string()), Val::Atom("b".to_string())))), + "(a b)".to_string() + ); + } +} diff --git a/lisp/src/eval.rs b/lisp/src/eval.rs new file mode 100644 index 0000000..2afe049 --- /dev/null +++ b/lisp/src/eval.rs @@ -0,0 +1,59 @@ +use crate::ast::Val; + +pub fn eval_f(f: &str, args: &[Val]) -> Val { + match f { + "quote" if args.len() == 1 => args[0].clone(), + _ => Val::Atom("error".to_string()), + } +} + +pub fn eval(v: &Val) -> Val { + match v { + v @ Val::Atom(_) => v.clone(), + v @ Val::I64(_) => v.clone(), + v @ Val::String(_) => v.clone(), + v @ Val::List(vs) => { + if vs.is_empty() { + return v.clone(); + } + match &vs[0] { + Val::Atom(f) => eval_f(&f, &vs[1..]), + _ => v.clone(), + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn eval_atom() { + assert_eq!( + eval(&Val::Atom("x".to_string())), + Val::Atom("x".to_string()) + ); + } + #[test] + fn eval_i64() { + assert_eq!(eval(&Val::I64(1)), Val::I64(1)); + } + #[test] + fn eval_string() { + assert_eq!( + eval(&Val::String("hello".to_string())), + Val::String("hello".to_string()) + ); + } + #[test] + fn eval_quote() { + assert_eq!( + eval(&Val::List(vec!( + Val::Atom("quote".to_string()), + Val::Atom("x".to_string()) + ))), + Val::Atom("x".to_string()) + ); + } +} diff --git a/lisp/src/lib.rs b/lisp/src/lib.rs index 60d0a4e..f880ec0 100644 --- a/lisp/src/lib.rs +++ b/lisp/src/lib.rs @@ -1,5 +1,7 @@ pub mod parser; pub mod ast; +pub mod eval; +pub mod primitives; pub fn my_fn() -> bool { true diff --git a/lisp/src/main.rs b/lisp/src/main.rs new file mode 100644 index 0000000..f21c425 --- /dev/null +++ b/lisp/src/main.rs @@ -0,0 +1,2 @@ +pub fn main() { +} diff --git a/lisp/src/primitives.rs b/lisp/src/primitives.rs new file mode 100644 index 0000000..68602b7 --- /dev/null +++ b/lisp/src/primitives.rs @@ -0,0 +1 @@ +use crate::ast::Val; -- cgit v1.2.3