96 lines
3 KiB
Rust
96 lines
3 KiB
Rust
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<'a>() -> impl Parser<Token<'a>, Vec<Spanned<Expr<'a>>>, Error = Simple<Token<'a>>> {
|
|
recursive(|expr| {
|
|
let atom = select! {
|
|
Token::Symbol(s) => Expr::Symbol(s.into()),
|
|
Token::Keyword(k) => Expr::Keyword(k.into()),
|
|
Token::String(s) => Expr::String(s.into()),
|
|
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)
|
|
.map(Box::new)
|
|
.map(Expr::Quote);
|
|
|
|
let without_pair = atom
|
|
.or(list)
|
|
.or(vector)
|
|
.or(quote)
|
|
.map_with_span(Spanned::new);
|
|
|
|
let pair = without_pair
|
|
.clone()
|
|
.then_ignore(just(Token::Dot))
|
|
.then(without_pair.clone())
|
|
.map(|(l, r)| Expr::Pair((Box::new(l), Box::new(r))))
|
|
.map_with_span(Spanned::new);
|
|
|
|
pair.or(without_pair)
|
|
})
|
|
.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".into()), 1..6),
|
|
Spanned::new(Expr::Symbol("hello".into()), 7..12),
|
|
Spanned::new(
|
|
Expr::List(vec![Spanned::new(Expr::Symbol("name".into()), 14..18),]),
|
|
13..19,
|
|
),
|
|
Spanned::new(
|
|
Expr::List(vec![
|
|
Spanned::new(Expr::Symbol("log".into()), 21..24),
|
|
Spanned::new(
|
|
Expr::List(vec![
|
|
Spanned::new(Expr::Symbol("concat".into()), 26..32),
|
|
Spanned::new(Expr::String("Hello, ".into()), 33..42),
|
|
Spanned::new(Expr::Symbol("name".into()), 43..47),
|
|
Spanned::new(Expr::String("!".into()), 48..51),
|
|
]),
|
|
48..51
|
|
)
|
|
]),
|
|
20..53
|
|
)
|
|
]),
|
|
0..54,
|
|
)]
|
|
);
|
|
}
|
|
}
|