1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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")
    }
}