use super::{ ast::{Expr, Spanned}, lexer::Token, }; use chumsky::{prelude::*, Stream}; use logos::Logos; /// Parse source string into a Expr pub fn parse(src: &str) -> Result<Vec<Spanned<Expr>>, Vec<Simple<Token<'_>>>> { let lexer = Token::lexer(src); let len = lexer.source().len(); parser().parse(Stream::from_iter(len..len + 1, lexer.spanned())) } fn parser<'s>() -> impl Parser<Token<'s>, Vec<Spanned<Expr<'s>>>, Error = Simple<Token<'s>>> { recursive(|expr| { let atom = select! { Token::Symbol(s) => Expr::Symbol(s), Token::Keyword(k) => Expr::Keyword(k), Token::String(s) => Expr::String(s), Token::Number(n) => Expr::Number(n), }; let list = expr .clone() .repeated() .delimited_by(just(Token::LeftParen), just(Token::RightParen)); let vector = just(Token::Octothorpe) .ignore_then(list.clone()) .map(Expr::Vector); let list = list.map(Expr::List); let quote = just(Token::Quote) .ignore_then(expr.clone()) .map(Box::new) .map(Expr::Quote); let pair = expr .clone() .then_ignore(just(Token::Dot)) .then(expr) .delimited_by(just(Token::LeftParen), just(Token::RightParen)) .map(|(l, r)| Expr::Pair((Box::new(l), Box::new(r)))); atom.or(pair) .or(list) .or(vector) .or(quote) .map_with_span(Spanned::new) }) .repeated() .then_ignore(end()) } #[cfg(test)] mod tests { use super::*; #[test] fn function() { assert_eq!( parse(r#"(defun hello (name) (log (concat "Hello, " name "!")))"#).unwrap(), &[Spanned::new( Expr::List(vec![ Spanned::new(Expr::Symbol("defun"), 1..6), Spanned::new(Expr::Symbol("hello"), 7..12), Spanned::new( Expr::List(vec![Spanned::new(Expr::Symbol("name"), 14..18),]), 13..19, ), Spanned::new( Expr::List(vec![ Spanned::new(Expr::Symbol("log"), 21..24), Spanned::new( Expr::List(vec![ Spanned::new(Expr::Symbol("concat"), 26..32), Spanned::new(Expr::String("Hello, "), 33..42), Spanned::new(Expr::Symbol("name"), 43..47), Spanned::new(Expr::String("!"), 48..51), ]), 48..51 ) ]), 20..53 ) ]), 0..54, )] ); } }