Skip to main content

aiken_lang/parser/expr/when/
clause.rs

1use super::guard;
2use crate::{
3    ast,
4    expr::UntypedExpr,
5    parser::{error::ParseError, pattern, token::Token},
6};
7use chumsky::prelude::*;
8use vec1::vec1;
9
10pub fn parser(
11    expression: Recursive<'_, Token, UntypedExpr, ParseError>,
12) -> impl Parser<Token, ast::UntypedClause, Error = ParseError> + '_ {
13    pattern()
14        .then(
15            choice((
16                just(Token::Vbar),
17                just(Token::VbarVbar),
18                just(Token::Or),
19                just(Token::Comma),
20            ))
21            .ignore_then(pattern())
22            .repeated()
23            .or_not(),
24        )
25        .then(choice((just(Token::If)
26            .ignore_then(guard())
27            .or_not()
28            .then_ignore(just(Token::RArrow)),)))
29        // TODO: add hint "Did you mean to wrap a multi line clause in curly braces?"
30        .then(expression)
31        .validate(
32            |(((pattern, alternative_patterns_opt), guard), then), span, emit| {
33                if guard.is_some() {
34                    emit(ParseError::deprecated_when_clause_guard(span));
35                }
36
37                (pattern, alternative_patterns_opt, then)
38            },
39        )
40        .map_with_span(|(pattern, alternative_patterns_opt, then), span| {
41            let mut patterns = vec1![pattern];
42            patterns.append(&mut alternative_patterns_opt.unwrap_or_default());
43            ast::UntypedClause {
44                location: span,
45                patterns,
46                then,
47            }
48        })
49}
50
51#[cfg(test)]
52mod tests {
53    use crate::assert_expr;
54
55    #[test]
56    fn when_clause_todo() {
57        assert_expr!(
58            r#"
59            when val is {
60              Bar1{..} -> True
61              Bar2{..} -> todo @"unimplemented"
62            }
63            "#
64        );
65    }
66
67    #[test]
68    fn when_clause_solo_error() {
69        assert_expr!(
70            r#"
71            when val is {
72              Bar1{..} -> fail
73            }
74            "#
75        );
76    }
77
78    #[test]
79    fn when_clause_double_todo() {
80        assert_expr!(
81            r#"
82            when val is {
83              Bar1{..} -> todo
84              Bar2{..} -> todo
85            }
86            "#
87        );
88    }
89
90    #[test]
91    fn when_clause_alternative() {
92        assert_expr!(
93            r#"
94            when val is {
95              Bar1{..} | Bar2{..} -> todo
96              Bar3{..} || Bar4{..} -> todo
97              Bar5{..} or Bar6{..} -> todo
98              Bar5{..}, Bar6{..} -> todo
99            }
100            "#
101        );
102    }
103}