Skip to main content

aiken_lang/parser/pattern/
constructor.rs

1use chumsky::prelude::*;
2
3use crate::{
4    ast::{CallArg, Namespace, Span, UntypedPattern},
5    parser::{error::ParseError, token::Token},
6};
7
8pub fn parser(
9    pattern: Recursive<'_, Token, UntypedPattern, ParseError>,
10) -> impl Parser<Token, UntypedPattern, Error = ParseError> + '_ {
11    choice((
12        select! { Token::Name { name } => name }
13            .then(just(Token::Dot).ignore_then(select! {Token::UpName { name } => name}))
14            .then(
15                just(Token::Dot).ignore_then(
16                    select! {Token::UpName { name } => name}.then(args(pattern.clone())),
17                ),
18            )
19            .map_with_span(
20                |((module, namespace), (name, (arguments, spread_location, is_record))), span| {
21                    UntypedPattern::Constructor {
22                        is_record,
23                        location: span,
24                        name,
25                        arguments,
26                        module: Some(Namespace::Type(Some(module), namespace)),
27                        constructor: (),
28                        spread_location,
29                        tipo: (),
30                    }
31                },
32            ),
33        select! { Token::UpName { name } => name }
34            .then(
35                just(Token::Dot).ignore_then(
36                    select! {Token::UpName { name } => name}.then(args(pattern.clone())),
37                ),
38            )
39            .map_with_span(
40                |(namespace, (name, (arguments, spread_location, is_record))), span| {
41                    UntypedPattern::Constructor {
42                        is_record,
43                        location: span,
44                        name,
45                        arguments,
46                        module: Some(Namespace::Type(None, namespace)),
47                        constructor: (),
48                        spread_location,
49                        tipo: (),
50                    }
51                },
52            ),
53        select! {Token::UpName { name } => name}
54            .then(args(pattern))
55            .map_with_span(
56                |(name, (arguments, spread_location, is_record)), location| {
57                    UntypedPattern::Constructor {
58                        is_record,
59                        location,
60                        name,
61                        arguments,
62                        module: None,
63                        constructor: (),
64                        spread_location,
65                        tipo: (),
66                    }
67                },
68            ),
69    ))
70}
71
72pub(crate) fn args(
73    pattern: Recursive<'_, Token, UntypedPattern, ParseError>,
74) -> impl Parser<Token, (Vec<CallArg<UntypedPattern>>, Option<Span>, bool), Error = ParseError> + '_
75{
76    let record_constructor_pattern_arg_parser = choice((
77        select! {Token::Name {name} => name}
78            .then_ignore(just(Token::Colon))
79            .then(pattern.clone())
80            .map_with_span(|(name, pattern), span| CallArg {
81                location: span,
82                label: Some(name),
83                value: pattern,
84            }),
85        select! {Token::Name{name} => name}.map_with_span(|name, span| CallArg {
86            location: span,
87            value: UntypedPattern::Var {
88                name: name.clone(),
89                location: span,
90            },
91            label: Some(name),
92        }),
93    ))
94    .separated_by(just(Token::Comma))
95    .allow_trailing()
96    .then(
97        just(Token::DotDot)
98            .ignored()
99            .map_with_span(|_spread, span| span)
100            .then_ignore(just(Token::Comma).or_not())
101            .or_not(),
102    )
103    .delimited_by(just(Token::LeftBrace), just(Token::RightBrace));
104
105    let tuple_constructor_pattern_arg_parser = pattern
106        .clone()
107        .map(|pattern| CallArg {
108            location: pattern.location(),
109            value: pattern,
110            label: None,
111        })
112        .separated_by(just(Token::Comma))
113        .allow_trailing()
114        .then(
115            just(Token::DotDot)
116                .ignored()
117                .map_with_span(|_spread, span| span)
118                .then_ignore(just(Token::Comma).or_not())
119                .or_not(),
120        )
121        .delimited_by(just(Token::LeftParen), just(Token::RightParen));
122
123    choice((
124        record_constructor_pattern_arg_parser.map(|a| (a, true)),
125        tuple_constructor_pattern_arg_parser.map(|a| (a, false)),
126    ))
127    .or_not()
128    .map(|opt_args| {
129        opt_args
130            .map(|((a, b), c)| (a, b, c))
131            .unwrap_or_else(|| (vec![], None, false))
132    })
133}
134
135#[cfg(test)]
136mod tests {
137    use crate::assert_pattern;
138
139    #[test]
140    fn constructor_basic() {
141        assert_pattern!("True");
142    }
143
144    #[test]
145    fn constructor_module_select() {
146        assert_pattern!("module.Foo");
147    }
148
149    #[test]
150    fn constructor_type_select() {
151        assert_pattern!("Foo.Bar");
152    }
153}