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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
use chumsky::Parser;
use chumsky::prelude::*;

use super::types::*;
use super::util::*;
use crate::lexer::Token;

#[derive(Debug, Clone)]
pub enum Function<'s> {
    Both(Spanned<Λ<'s>>, usize),
    And(Vec<Spanned<Λ<'s>>>),
    Take(u64),
    If { then: Λ<'s>, or: Λ<'s> },
    Array(Option<u64>),
    Append,
    Map(Spanned<Λ<'s>>),
    Dup,
    Flip,
    Eq,
    Reverse,
    Zap(Option<u64>),
    Del,
    Debug,
    Add,
    Sub,
    IndexHashMap,
    Not,
    Mul,
    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,
    Setify,
    Ident(&'s str),
    Define(&'s str),
}

impl<'s> Λ<'s> {
    pub 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 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::Mul => Mul,
            Token::Pow => Pow,
            Token::Sqrt => Sqrt,
            Token::Lt => Lt,
            Token::Not => Not,
            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::Split => Split,
            Token::First => First,
            Token::Ne => Ne,
            Token::Type => Type,
            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::<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![Fold],
            one![Map],
            one![With],
            just(Token::Zap).ignore_then(t![int]).map(Some).map(Zap),
            t!['['].ignore_then(t![int]).map(Take),
            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")
    }
}