1use chumsky::prelude::*;
2use vec1::Vec1;
3
4mod and_or_chain;
5mod anonymous_binop;
6pub mod anonymous_function;
7pub mod assignment;
8mod block;
9pub(crate) mod bytearray;
10mod chained;
11mod fail_todo_trace;
12mod if_else;
13mod int;
14mod list;
15mod pair;
16mod record;
17mod record_update;
18mod sequence;
19pub mod string;
20mod tuple;
21mod var;
22pub mod when;
23
24use super::{error::ParseError, token::Token};
25use crate::{ast, expr::UntypedExpr};
26pub use and_or_chain::parser as and_or_chain;
27pub use anonymous_function::parser as anonymous_function;
28pub use block::parser as block;
29pub use bytearray::parser as bytearray;
30pub use chained::parser as chained;
31pub use fail_todo_trace::parser as fail_todo_trace;
32pub use if_else::parser as if_else;
33pub use int::parser as int;
34pub use list::parser as list;
35pub use pair::parser as pair;
36pub use record::parser as record;
37pub use record_update::parser as record_update;
38pub use sequence::parser as sequence;
39pub use string::parser as string;
40pub use tuple::parser as tuple;
41pub use var::parser as var;
42pub use when::parser as when;
43
44pub fn parser(
45 sequence: Recursive<'_, Token, UntypedExpr, ParseError>,
46) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
47 recursive(|expression| {
48 choice((
49 fail_todo_trace(expression.clone(), sequence.clone()),
50 pure_expression(sequence, expression),
51 ))
52 })
53}
54
55pub fn pure_expression<'a>(
56 sequence: Recursive<'a, Token, UntypedExpr, ParseError>,
57 expression: Recursive<'a, Token, UntypedExpr, ParseError>,
58) -> impl Parser<Token, UntypedExpr, Error = ParseError> + 'a {
59 let op = choice((
61 just(Token::Bang).to(ast::UnOp::Not),
62 choice((just(Token::Minus), just(Token::NewLineMinus)))
63 .then_ignore(just(Token::Comma).not().rewind())
75 .to(ast::UnOp::Negate),
76 ));
77
78 let unary = op
79 .map_with_span(|op, span| (op, span))
80 .repeated()
81 .then(chained(sequence, expression))
82 .foldr(|(un_op, span), value| UntypedExpr::UnOp {
83 op: un_op,
84 location: span.union(value.location()),
85 value: Box::new(value),
86 })
87 .boxed();
88
89 let op = choice((
91 just(Token::Star).to(ast::BinOp::MultInt),
92 just(Token::Slash).to(ast::BinOp::DivInt),
93 just(Token::Percent).to(ast::BinOp::ModInt),
94 ));
95
96 let product = unary
97 .clone()
98 .then(op.then(unary).repeated())
99 .foldl(|a, (op, b)| UntypedExpr::BinOp {
100 location: a.location().union(b.location()),
101 name: op,
102 left: Box::new(a),
103 right: Box::new(b),
104 })
105 .boxed();
106
107 let op = choice((
109 just(Token::Plus).to(ast::BinOp::AddInt),
110 just(Token::Minus).to(ast::BinOp::SubInt),
111 ));
112
113 let sum = product
114 .clone()
115 .then(op.then(product).repeated())
116 .foldl(|a, (op, b)| UntypedExpr::BinOp {
117 location: a.location().union(b.location()),
118 name: op,
119 left: Box::new(a),
120 right: Box::new(b),
121 })
122 .boxed();
123
124 let op = choice((
126 just(Token::EqualEqual).to(ast::BinOp::Eq),
127 just(Token::NotEqual).to(ast::BinOp::NotEq),
128 just(Token::Less).to(ast::BinOp::LtInt),
129 just(Token::Greater).to(ast::BinOp::GtInt),
130 just(Token::LessEqual).to(ast::BinOp::LtEqInt),
131 just(Token::GreaterEqual).to(ast::BinOp::GtEqInt),
132 ));
133
134 let comparison = sum
135 .clone()
136 .then(op.then(sum).repeated())
137 .foldl(|a, (op, b)| UntypedExpr::BinOp {
138 location: a.location().union(b.location()),
139 name: op,
140 left: Box::new(a),
141 right: Box::new(b),
142 })
143 .boxed();
144
145 let op = just(Token::AmperAmper).to(ast::BinOp::And);
159 let conjunction = comparison
160 .clone()
161 .map(|e| vec![e])
162 .clone()
163 .then(op.then(comparison).repeated())
164 .foldl(|a, (_op, b)| {
165 let mut tail = vec![b];
166 tail.extend(a);
167 tail
168 })
169 .map(|xs| {
170 xs.into_iter()
171 .reduce(|right, left| UntypedExpr::BinOp {
172 location: left.location().union(right.location()),
173 name: ast::BinOp::And,
174 left: Box::new(left),
175 right: Box::new(right),
176 })
177 .unwrap()
178 })
179 .boxed();
180
181 let op = just(Token::VbarVbar).to(ast::BinOp::Or);
184 let disjunction = conjunction
185 .clone()
186 .map(|e| vec![e])
187 .then(op.then(conjunction).repeated())
188 .foldl(|a, (_op, b)| {
189 let mut tail = vec![b];
190 tail.extend(a);
191 tail
192 })
193 .map(|xs| {
194 xs.into_iter()
195 .reduce(|right, left| UntypedExpr::BinOp {
196 location: left.location().union(right.location()),
197 name: ast::BinOp::Or,
198 left: Box::new(left),
199 right: Box::new(right),
200 })
201 .unwrap()
202 })
203 .boxed();
204
205 disjunction
207 .clone()
208 .then(
209 choice((just(Token::Pipe), just(Token::NewLinePipe)))
210 .then(disjunction)
211 .repeated(),
212 )
213 .foldl(|l, (pipe, r)| {
214 if let UntypedExpr::PipeLine {
215 mut expressions,
216 one_liner,
217 } = l
218 {
219 expressions.push(r);
220 return UntypedExpr::PipeLine {
221 expressions,
222 one_liner,
223 };
224 }
225
226 let mut expressions = Vec1::new(l);
227 expressions.push(r);
228 UntypedExpr::PipeLine {
229 expressions,
230 one_liner: pipe != Token::NewLinePipe,
231 }
232 })
233}
234
235#[cfg(test)]
236mod tests {
237 use crate::assert_expr;
238
239 #[test]
240 fn plus_binop() {
241 assert_expr!("a + 1");
242 }
243
244 #[test]
245 fn pipeline() {
246 assert_expr!(
247 r#"
248 a + 2
249 |> add_one
250 |> add_one
251 "#
252 );
253 }
254
255 #[test]
256 fn field_access() {
257 assert_expr!("user.name");
258 }
259
260 #[test]
261 fn function_invoke() {
262 assert_expr!(
263 r#"
264 let x = add_one(3)
265
266 let map_add_x = list.map(_, fn (y) { x + y })
267
268 map_add_x([ 1, 2, 3 ])
269 "#
270 );
271 }
272}