summaryrefslogtreecommitdiff
path: root/lisp/src
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/src')
-rw-r--r--lisp/src/ast.rs7
-rw-r--r--lisp/src/lib.rs16
-rw-r--r--lisp/src/parser.rs77
3 files changed, 100 insertions, 0 deletions
diff --git a/lisp/src/ast.rs b/lisp/src/ast.rs
new file mode 100644
index 0000000..8cac963
--- /dev/null
+++ b/lisp/src/ast.rs
@@ -0,0 +1,7 @@
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum Val {
+ Atom(String),
+ List(Vec<Self>),
+ I64(i64),
+ String(String),
+}
diff --git a/lisp/src/lib.rs b/lisp/src/lib.rs
new file mode 100644
index 0000000..60d0a4e
--- /dev/null
+++ b/lisp/src/lib.rs
@@ -0,0 +1,16 @@
+pub mod parser;
+pub mod ast;
+
+pub fn my_fn() -> bool {
+ true
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ assert!(my_fn());
+ }
+}
diff --git a/lisp/src/parser.rs b/lisp/src/parser.rs
new file mode 100644
index 0000000..e36bdf7
--- /dev/null
+++ b/lisp/src/parser.rs
@@ -0,0 +1,77 @@
+use chumsky::prelude::*;
+
+use crate::ast::Val;
+
+pub fn parser<'a>() -> impl Parser<char, Vec<Val>, Error = Simple<char>> {
+ recursive(|val| {
+ let string = just('"')
+ .ignore_then(none_of('"').repeated())
+ .then_ignore(just('"'))
+ .collect::<String>()
+ .map(Val::String)
+ .padded();
+
+ let atom = filter(|c: &char| c.is_alphanumeric())
+ .map(Some)
+ .chain::<char, _, _>(filter(|c: &char| c.is_alphanumeric()).repeated())
+ .collect::<String>()
+ .map(Val::Atom)
+ .padded();
+
+ let number = just('-')
+ .or_not()
+ .chain::<char, _, _>(text::int(10))
+ .collect::<String>()
+ .from_str()
+ .unwrapped()
+ .map(Val::I64)
+ .labelled("number");
+
+ choice((
+ string, //
+ number,
+ atom,
+ val.delimited_by(just('('), just(')')).map(Val::List),
+ ))
+ .repeated()
+ })
+ .then_ignore(end())
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn parse_atom() {
+ assert_eq!(
+ Ok(vec!(Val::Atom("foo".to_string()))),
+ parser().parse("foo")
+ );
+ }
+
+ #[test]
+ fn parse_string() {
+ assert_eq!(
+ Ok(vec!(Val::String("foo".to_string()))),
+ parser().parse("\"foo\"")
+ );
+ }
+
+ #[test]
+ fn parse_i64() {
+ assert_eq!(Ok(vec!(Val::I64(123))), parser().parse("123"));
+ assert_eq!(Ok(vec!(Val::I64(-643))), parser().parse("-643"));
+ }
+
+ #[test]
+ fn parse_list() {
+ assert_eq!(
+ Ok(vec!(Val::List(vec!(
+ Val::Atom("a".to_string()),
+ Val::Atom("b".to_string())
+ )))),
+ parser().parse("(a b)")
+ );
+ }
+}