use chumsky::Parser; use chumsky::prelude::*; use super::types::*; use super::util::*; use crate::exec::Argc; use crate::lexer::Token; #[derive(Debug, Clone)] pub enum Function<'s> { Both(Spanned<Λ<'s>>, usize), And(Vec>>), Take(u64), If { then: Λ<'s>, or: Λ<'s> }, Array(Option), Append, Map(Spanned<Λ<'s>>), Dup, Flip, Python(Argc), Matches, Eq, Reverse, Zap(Option), Del, Debug, Add, Sub, IndexHashMap, Not, Mul, Windows, Pow, Type, Ne, Merge, Sqrt, Lt, Gt, Ge, Le, Shl, Shr, Neg, BitAnd, Length, Or, Xor, Div, Fold(Spanned<Λ<'s>>), Mod, Index, Mask, Group, Split, Open, First, Last, Reduce(Spanned<Λ<'s>>), Range, With(Spanned<Λ<'s>>), HashMap, Call, Sort, Zip, Identity, EmptySet, In, Setify, Ident(&'s str), Define(&'s str), } impl<'s> Λ<'s> { pub fn parse( exp: parser![Spanned>], ) -> parser![Spanned] { 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 fn parse(λ: parser![Λ<'s>]) -> parser![Self] { use Function::*; let basic = select! { Token::Dup => Dup, Token::Debug => Debug, Token::Flip => Flip, // Token::Reverse => Reverse, Token::Zap => Zap(None), Token::Add => Add, Token::ClosingBracket('}') => Setify, Token::Set => EmptySet, Token::Identity => Identity, Token::Del => Del, Token::HashMap => HashMap, Token::Get => IndexHashMap, Token::Sub => Sub, Token::Windows => Windows, Token::Mul => Mul, Token::Pow => Pow, Token::Sqrt => Sqrt, Token::Lt => Lt, Token::Not => Not, Token::In => In, Token::Index => Index, Token::Merge => Merge, Token::Shl => Shl, Token::Group => Group, Token::Shr => Shr, Token::Append => Append, Token::Neg => Neg, Token::Eq => Eq, Token::Gt => Gt, Token::Ge => Ge, Token::Length => Length, Token::Range => Range, Token::Le => Le, Token::BitAnd => BitAnd, Token::Or => Or, Token::Xor => Xor, Token::Sort => Sort, Token::Zip => Zip, Token::Div => Div, Token::Mod => Mod, Token::Open => Open, Token::Mask => Mask, Token::First => First, Token::Ne => Ne, Token::Type => Type, Token::Matches => Matches, Token::Last => Last, Token::Ident(x) => Ident(x), } .labelled("token"); let fn_param = choice(( 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::>(), ) .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![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::ArrayN) .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"), basic, )) .boxed() .labelled("function") } }