aiken_lang/parser/expr/
assignment.rs

1use crate::{
2    ast::{self, Span},
3    expr::UntypedExpr,
4    parser::{annotation, error::ParseError, pattern, token::Token},
5};
6use chumsky::prelude::*;
7
8pub fn let_(
9    r: Recursive<'_, Token, UntypedExpr, ParseError>,
10) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
11    just(Token::Let)
12        .ignore_then(assignment_patterns())
13        .then(choice((just(Token::Equal), just(Token::LArrow))))
14        .then(r.clone())
15        .validate(move |((patterns, kind), value), span, emit| {
16            if matches!(value, UntypedExpr::Assignment { .. }) {
17                emit(ParseError::invalid_assignment_right_hand_side(span))
18            }
19
20            let patterns = patterns
21                .try_into()
22                .expect("We use at_least(1) so this should never be empty");
23
24            UntypedExpr::Assignment {
25                location: span,
26                value: Box::new(value),
27                patterns,
28                kind: ast::AssignmentKind::Let {
29                    backpassing: kind == Token::LArrow,
30                },
31            }
32        })
33}
34
35fn assignment_patterns() -> impl Parser<Token, Vec<ast::AssignmentPattern>, Error = ParseError> {
36    assignment_pattern()
37        .separated_by(just(Token::Comma))
38        .allow_trailing()
39        .at_least(1)
40}
41
42pub fn assignment_pattern() -> impl Parser<Token, ast::AssignmentPattern, Error = ParseError> {
43    pattern()
44        .then(just(Token::Colon).ignore_then(annotation()).or_not())
45        .map_with_span(|(pattern, annotation), span| ast::AssignmentPattern {
46            pattern,
47            annotation,
48            location: span,
49        })
50}
51
52pub fn expect(
53    r: Recursive<'_, Token, UntypedExpr, ParseError>,
54) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
55    just(Token::Expect)
56        .ignore_then(
57            assignment_patterns()
58                .then(choice((just(Token::Equal), just(Token::LArrow))))
59                .or_not(),
60        )
61        .then(r.clone())
62        .validate(move |(opt_pattern, value), span, emit| {
63            if matches!(value, UntypedExpr::Assignment { .. }) {
64                emit(ParseError::invalid_assignment_right_hand_side(span))
65            }
66
67            let (patterns, kind) = opt_pattern.unwrap_or_else(|| {
68                let filler_true = ast::AssignmentPattern::new(
69                    ast::UntypedPattern::true_(span),
70                    None,
71                    Span::empty(),
72                );
73
74                (vec![filler_true], Token::Equal)
75            });
76
77            let patterns = patterns
78                .try_into()
79                .expect("We use at_least(1) so this should never be empty");
80
81            UntypedExpr::Assignment {
82                location: span,
83                patterns,
84                value: Box::new(value),
85                kind: ast::AssignmentKind::Expect {
86                    backpassing: kind == Token::LArrow,
87                },
88            }
89        })
90}
91
92#[cfg(test)]
93mod tests {
94    use crate::assert_expr;
95
96    #[test]
97    fn let_bindings() {
98        assert_expr!("let thing = [ 1, 2, a ]");
99    }
100
101    #[test]
102    fn expect() {
103        assert_expr!("expect Some(x) = something.field");
104    }
105
106    #[test]
107    fn expect_bool_sugar() {
108        assert_expr!("expect something.field == wow");
109    }
110
111    #[test]
112    fn expect_trace_if_false() {
113        assert_expr!("expect foo?");
114    }
115
116    #[test]
117    fn expect_unfinished_let() {
118        assert_expr!(
119            "
120            let a =
121            // foo
122            let b = 42
123            "
124        );
125    }
126
127    #[test]
128    fn expect_let_in_let() {
129        assert_expr!("let a = { let b = 42 }");
130    }
131
132    #[test]
133    fn expect_let_in_let_return() {
134        assert_expr!(
135            "
136            let a = {
137              let b = 42
138              b
139            }
140            "
141        );
142    }
143
144    #[test]
145    fn expect_let_in_let_parens() {
146        assert_expr!("let a = ( let b = 42 )");
147    }
148
149    #[test]
150    fn expect_expect_let() {
151        assert_expr!("expect { let a = 42 } = foo");
152    }
153}