aiken_lang/parser/pattern/
constructor.rs1use 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}