Diffstat (limited to 'src/parser.rs')
-rw-r--r--src/parser.rs81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/parser.rs b/src/parser.rs
new file mode 100644
index 0000000..df5af22
--- /dev/null
+++ b/src/parser.rs
@@ -0,0 +1,81 @@
+mod types;
+use crate::lexer::{Lexer, Token};
+use chumsky::{
+ input::{SpannedInput, Stream},
+ prelude::*,
+ Parser,
+};
+mod util;
+use types::*;
+use util::*;
+
+impl<'s> Value<'s> {
+ pub fn parse() -> parser![Self] {
+ select! {
+ Token::Int(x) => Value::Int(x),
+ Token::Float(x) => Value::Float(x),
+ Token::String(s) => Value::String(s),
+ }
+ .labelled("value")
+ }
+}
+
+impl<'s> Expr<'s> {
+ pub fn parse() -> parser![Self] {
+ recursive::<_, Expr, _, _, _>(|expr| {
+ let inline_expr = recursive(|inline_expr| {
+ let val = select! {
+ Token::Int(x) => Expr::Value(Value::Int(x)),
+ Token::Float(x) => Expr::Value(Value::Float(x)),
+ Token::String(s) => Expr::Value(Value::String(s)),
+ }
+ .labelled("value");
+
+ choice((t![ident].map(Expr::Ident), val)).boxed()
+ });
+
+ let λ = t![λ].ignore_then(expr.clone().delimited_by(t!['('], t![')']));
+
+ let decl = t![ident]
+ .then_ignore(t![<-])
+ .then(inline_expr.clone().or(λ.clone()))
+ .map(|(name, body)| Expr::Let {
+ name,
+ rhs: Box::new(body),
+ })
+ .labelled("declare")
+ .boxed();
+
+ let r#if = t![if]
+ .ignore_then(
+ expr.clone()
+ .then(t![else].or_not().ignore_then(expr.or_not()))
+ .delimited_by(t!['('], t![')']),
+ )
+ .map(|(a, b)| Expr::If {
+ then: Box::new(a),
+ or: Box::new(b.unwrap_or_else(|| Expr::Value(Value::Unit))),
+ })
+ .labelled("if")
+ .boxed();
+ choice((decl, r#if, inline_expr, λ))
+ })
+ }
+}
+
+pub fn stream(lexer: Lexer<'_>, len: usize) -> SpannedInput<Token<'_>, Span, Stream<Lexer<'_>>> {
+ Stream::from_iter(lexer).spanned((len..len).into())
+}
+
+#[cfg(test)]
+pub fn code<'s>(x: &'s str) -> SpannedInput<Token<'s>, Span, Stream<Lexer<'s>>> {
+ stream(crate::lexer::lex(x), x.len())
+}
+
+pub fn parse(tokens: Lexer<'_>, len: usize) -> Result<Ast<'_>, Vec<Error<'_>>> {
+ parser().parse(stream(tokens, len)).into_result()
+}
+
+fn parser<'s>() -> parser![Ast<'s>] {
+ Expr::parse().repeated().collect().map(Ast::Module)
+}