use chumsky::prelude::*; use crate::ast::Val; pub fn parser<'a>() -> impl Parser, Error = Simple> { recursive(|val| { let string = just('"') .ignore_then(none_of('"').repeated()) .then_ignore(just('"')) .collect::() .map(Val::String) .padded(); let atom = filter(|c: &char| c.is_alphanumeric()) .map(Some) .chain::(filter(|c: &char| c.is_alphanumeric()).repeated()) .collect::() .map(Val::Atom) .padded(); let number = just('-') .or_not() .chain::(text::int(10)) .collect::() .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)") ); } }