wisp/src/syntax/parser.rs
2022-08-06 21:28:12 +02:00

94 lines
2.9 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<'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,
)]
);
}
}