tmp
| -rw-r--r-- | src/main.rs | 1 | ||||
| -rw-r--r-- | src/parser.rs | 34 | ||||
| -rw-r--r-- | src/parser/fun.rs | 54 | ||||
| -rw-r--r-- | src/parser/types.rs | 4 | ||||
| -rw-r--r-- | src/parser/util.rs | 2 | ||||
| -rw-r--r-- | src/ui.rs | 42 |
6 files changed, 101 insertions, 36 deletions
diff --git a/src/main.rs b/src/main.rs index 18bd388..4499d9b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ mod array; mod lexer; mod parser; +mod ui; fn main() { println!("Hello, world!"); } diff --git a/src/parser.rs b/src/parser.rs index 8cee0ef..e90f11e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,15 +1,17 @@ -mod types; +pub mod types; use crate::lexer::{Lexer, Token}; use chumsky::{ input::{SpannedInput, Stream}, prelude::*, Parser, }; -mod fun; -mod util; +pub mod fun; +pub mod util; use types::*; use util::*; +use self::fun::Function; + impl<'s> Value<'s> { pub fn parse() -> parser![Self] { select! { @@ -35,11 +37,11 @@ impl<'s> Expr<'s> { choice((t![ident].map(Expr::Ident), val)).boxed() }); - let λ = Lambda::parse().map(Expr::Lambda); + let λ = Λ::parse(expr.clone()); let decl = t![ident] .then_ignore(t![<-]) - .then(inline_expr.clone().or(λ.clone())) + .then(inline_expr.clone().or(λ.clone().map(Expr::Lambda))) .map(|(name, body)| Expr::Let { name, rhs: Box::new(body), @@ -50,7 +52,7 @@ impl<'s> Expr<'s> { let r#if = t![if] .ignore_then( expr.clone() - .then(t![else].or_not().ignore_then(expr.or_not())) + .then(t![else].or_not().ignore_then(expr.clone().or_not())) .delimited_by(t!['('], t![')']), ) .map(|(a, b)| Expr::If { @@ -59,14 +61,22 @@ impl<'s> Expr<'s> { }) .labelled("🐋") .boxed(); - choice((decl, r#if, inline_expr, λ)) + choice(( + decl, + r#if, + inline_expr, + λ.clone().map(Expr::Lambda), + Function::parse(λ).map(Expr::Function), + )) + .labelled("expr") }) } } #[test] fn parse_expr() { - dbg!(Expr::parse().parse(code("a ← λ ( +- 🍴 )")).unwrap()); + parse_s("a ← λ ( +- 🍴 )", Expr::parse()); + // dbg!(Expr::parse().parse(code("a ← λ ( +- 🍴 )")).unwrap()); } pub fn stream(lexer: Lexer<'_>, len: usize) -> SpannedInput<Token<'_>, Span, Stream<Lexer<'_>>> { @@ -78,6 +88,14 @@ pub fn code<'s>(x: &'s str) -> SpannedInput<Token<'s>, Span, Stream<Lexer<'s>>> stream(crate::lexer::lex(x), x.len()) } +#[cfg(test)] +pub fn parse_s<'s, T: std::fmt::Debug>(x: &'s str, p: parser![T]) -> T { + match crate::ui::display(p.parse(code(x)).into_result(), x) { + Ok(x) => dbg!(x), + Err(()) => panic!(), + } +} + pub fn parse(tokens: Lexer<'_>, len: usize) -> Result<Ast<'_>, Vec<Error<'_>>> { parser().parse(stream(tokens, len)).into_result() } diff --git a/src/parser/fun.rs b/src/parser/fun.rs index 9dfd561..3a4c01c 100644 --- a/src/parser/fun.rs +++ b/src/parser/fun.rs @@ -6,12 +6,12 @@ use chumsky::{prelude::*, Parser}; #[derive(Debug, Clone)] pub enum Function<'s> { Dup, - Both(Lambda<'s>, Lambda<'s>), - Fork(Lambda<'s>, Lambda<'s>), - Gap(Lambda<'s>), - Hold(Lambda<'s>), + Both(Λ<'s>, Λ<'s>), + Fork(Λ<'s>, Λ<'s>), + Gap(Λ<'s>), + Hold(Λ<'s>), Flip, - Duck(Lambda<'s>), + Duck(Λ<'s>), Reverse, Zap, Add, @@ -36,28 +36,28 @@ pub enum Function<'s> { Split, First, Last, - Each(Lambda<'s>), - Reduce(Lambda<'s>), - ReduceStack(Lambda<'s>), + Each(Λ<'s>), + Reduce(Λ<'s>), + ReduceStack(Λ<'s>), Range, Call, } -impl<'s> Lambda<'s> { - pub fn parse() -> parser![Self] { - t![λ] - .ignore_then( - Expr::parse() - .repeated() - .collect() - .delimited_by(t!['('], t![')']), - ) - .map(|x| Self(x)) +impl<'s> Λ<'s> { + pub fn parse(exp: parser![Expr<'s>]) -> parser![Self] { + let mut λ = Recursive::declare(); + λ.define(choice(( + t![λ] + .ignore_then(exp.repeated().collect().delimited_by(t!['('], t![')'])) + .map(|x| Self(x)), + Function::parse(λ.clone()).map(|x| Λ(vec![Expr::Function(x)])), + ))); + λ.labelled("λ") } } impl<'s> Function<'s> { - pub fn parse() -> parser![Self] { + pub fn parse(λ: parser![Λ<'s>]) -> parser![Self] { use Function::*; let basic = select! { Token::Dup => Dup, @@ -88,12 +88,16 @@ impl<'s> Function<'s> { Token::Last => Last, }; macro_rules! two { - ($name:ident) => { - Lambda::parse() - .then(Lambda::parse()) - .then_ignore(just(Token::$name)) - .map(|(a, b)| $name(a, b)) - }; + ($name:ident) => {{ + let mut p = Recursive::declare(); + p.define( + λ.clone() + .then(λ.clone()) + .then_ignore(just(Token::$name)) + .map(|(a, b)| $name(a, b)), + ); + p + }}; } choice((basic, two![Both], two![Fork])) } diff --git a/src/parser/types.rs b/src/parser/types.rs index 2385564..e050890 100644 --- a/src/parser/types.rs +++ b/src/parser/types.rs @@ -16,7 +16,7 @@ pub enum Ast<'s> { } #[derive(Clone, Debug)] -pub struct Lambda<'s>(pub Vec<Expr<'s>>); +pub struct Λ<'s>(pub Vec<Expr<'s>>); #[derive(Clone)] pub enum Value<'s> { @@ -43,7 +43,7 @@ pub enum Expr<'s> { Function(super::fun::Function<'s>), Value(Value<'s>), Ident(&'s str), - Lambda(Lambda<'s>), + Lambda(Λ<'s>), Let { name: &'s str, rhs: Box<Expr<'s>>, diff --git a/src/parser/util.rs b/src/parser/util.rs index 60c242a..42ff5d2 100644 --- a/src/parser/util.rs +++ b/src/parser/util.rs @@ -52,7 +52,7 @@ macro_rules! t { } macro_rules! parser { ($t:ty) => { - impl Parser<'s, crate::parser::types::Input<'s>, $t, extra::Err<Error<'s>>> + Clone + impl Parser<'s, crate::parser::types::Input<'s>, $t, extra::Err<Error<'s>>> + Clone + 's } } diff --git a/src/ui.rs b/src/ui.rs new file mode 100644 index 0000000..9c3dcd9 --- /dev/null +++ b/src/ui.rs @@ -0,0 +1,42 @@ +use crate::parser::types::Error; +use chumsky::{error::RichReason, prelude::*}; +use comat::cformat as cmt; + +pub fn display<T>(result: Result<T, Vec<Error>>, code: &str) -> Result<T, ()> { + let e = match result { + Ok(x) => return Ok(x), + Err(e) => e, + }; + + for e in e.into_iter().map(|e| e.map_token(|c| c.to_string())) { + let mut o = lerr::Error::new(code); + o.label((e.span().into_range(), "here")); + match e.reason() { + RichReason::Custom(x) => { + o.message(cmt!("{red}error{reset}: {x}")); + } + RichReason::ExpectedFound { .. } => { + o.message(cmt!("{red}error{reset}: {e}")); + } + RichReason::Many(x) => { + match &x[..] { + [x, rest @ ..] => { + o.message(cmt!("{red}error{reset}: {x}")); + for elem in rest { + o.note(cmt!("{yellow}also{reset}: {elem}")); + } + } + _ => unreachable!(), + }; + } + } + for (l, span) in e.contexts() { + o.label(( + span.into_range(), + cmt!("{yellow}while parsing this{reset}: {l}"), + )); + } + eprintln!("{o}"); + } + Err(()) +} |