use chumsky::Parser;
use chumsky::prelude::*;
use super::types::{Spanned, *};
use super::util::*;
use crate::exec::Argc;
use crate::lexer::Token;
impl<'s> Λ<'s> {
pub(crate) fn parse(
exp: parser![Spanned<Expr<'s>>],
) -> parser![Spanned<Self>] {
exp.repeated()
.collect()
.delimited_by(t!['('], t![')'])
.map_with(|x, e| Spanned::from((Self::of(x), e.span())))
.labelled("lambda")
}
}
impl<'s> Function<'s> {
pub(crate) fn parse(λ: parser![Λ<'s>]) -> parser![Self] {
use Function::*;
let fn_param = choice((
Self::basic()
.map_with(|x, e| {
Λ::of(vec![Expr::Function(x).spun(e.span())])
})
.labelled("function"),
λ.clone(),
))
.labelled("operand");
macro_rules! one {
($name:ident) => {
fn_param
.clone()
.then_ignore(just(Token::$name))
.map_with(spanned!())
.map($name)
.labelled(stringify!($name))
};
}
macro_rules! two {
($name:ident) => {
fn_param
.clone()
.map_with(spanned!())
.then(fn_param.clone().map_with(spanned!()))
.then_ignore(just(Token::$name))
.map(|(a, b)| $name(a, b))
.labelled(stringify!($name))
};
}
choice((
λ.clone()
.map_with(spanned!())
.then(
fn_param
.clone()
.map_with(spanned!())
.repeated()
.at_least(1)
.collect::<Vec<_>>(),
)
.then_ignore(just(Token::And))
.map(|(a, mut b)| {
b.insert(0, a);
And(b)
})
.boxed(),
fn_param
.clone()
.map_with(spanned!())
.then(
just(Token::Both)
.repeated()
.at_least(1)
.count()
.map(|x| x + 1),
)
.map(|(a, b)| Both(a, b))
.labelled("both"),
one![Reduce],
one![Scan],
one![Fold],
one![Map],
one![With],
just(Token::Zap).ignore_then(t![int]).map(Some).map(Zap),
t!['['].ignore_then(t![int]).map(Take),
just(Token::Python)
.ignore_then(t![int])
.then_ignore(t![->])
.then(t![int])
.map(|(a, b)| Python(Argc::takes(a as _).into(b as _))),
choice((
just(Token::Array)
.ignore_then(t![int].map(|x| Array(Some(x)))),
t![']'].map(|_| Array(None)),
))
.labelled("array")
.boxed(),
fn_param
.clone()
.then(fn_param.clone())
.then_ignore(just(Token::If))
.map(|(then, or)| If { then, or })
.labelled("if-else")
.boxed(),
fn_param
.clone()
.then_ignore(just(Token::EagerIf).labelled("if"))
.map(|then| If {
then,
or: Λ::default(),
})
.labelled("if")
.boxed(),
t![->].ignore_then(t![ident]).map(Define).labelled("def"),
Self::basic(),
))
.boxed()
.labelled("function")
}
}