summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2023-11-19 19:28:42 -0500
committerKjetil Orbekk <kj@orbekk.com>2023-11-19 19:28:54 -0500
commit465c3a1045625d12a73e723651ae9bd9b0a51cb1 (patch)
treed0a70280523b651be3510391d1ed0aa3933c96e5
parent79a31f87b668f9ef67a8cd6bc7826031fe3be18e (diff)
lisp eval
-rw-r--r--lisp/src/ast.rs59
-rw-r--r--lisp/src/eval.rs59
-rw-r--r--lisp/src/lib.rs2
-rw-r--r--lisp/src/main.rs2
-rw-r--r--lisp/src/primitives.rs1
5 files changed, 122 insertions, 1 deletions
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<Self>),
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;