1#[macro_use]
2use crate::*;
3
4pub fn pattern(input: ParseString) -> ParseResult<Pattern> {
6 match pattern_atom_struct(input.clone()) {
7 Ok((input, tpl)) => {return Ok((input, Pattern::TupleStruct(tpl)))},
8 _ => ()
9 }
10 match pattern_tuple_struct(input.clone()) {
11 Ok((input, tpl)) => {return Ok((input, Pattern::TupleStruct(tpl)))},
12 _ => ()
13 }
14 match wildcard(input.clone()) {
15 Ok((input, _)) => {return Ok((input, Pattern::Wildcard))},
16 _ => ()
17 }
18 match pattern_array(input.clone()) {
19 Ok((input, arr)) => {return Ok((input, Pattern::Array(arr)))},
20 _ => ()
21 }
22 match pattern_tuple(input.clone()) {
23 Ok((input, tpl)) => {return Ok((input, Pattern::Tuple(tpl)))},
24 _ => ()
25 }
26 match expression(input.clone()) {
27 Ok((input, expr)) => {return Ok((input, Pattern::Expression(expr)))},
28 Err(err) => {return Err(err)},
29 }
30}
31
32pub fn wildcard(input: ParseString) -> ParseResult<Pattern> {
34 let ((input, _)) = asterisk(input)?;
35 Ok((input, Pattern::Wildcard))
36}
37
38pub fn pattern_tuple_struct(input: ParseString) -> ParseResult<PatternTupleStruct> {
40 let (input, _) = grave(input)?;
41 let (input, id) = identifier(input)?;
42 let (input, _) = left_parenthesis(input)?;
43 let (input, _) = whitespace0(input)?;
44 let (input, patterns) = separated_list1(list_separator, pattern)(input)?;
45 let (input, _) = whitespace0(input)?;
46 let (input, _) = right_parenthesis(input)?;
47 Ok((input, PatternTupleStruct{name: id, patterns}))
48}
49
50fn spread_operator(input: ParseString) -> ParseResult<()> {
51 let (input, _) = alt((tag("..."), tag("…")))(input)?;
52 Ok((input, ()))
53}
54
55fn pattern_array_item(input: ParseString) -> ParseResult<Pattern> {
56 if let Ok((input, _)) = wildcard(input.clone()) {
57 return Ok((input, Pattern::Wildcard));
58 }
59 let (input, expr) = expression(input)?;
60 Ok((input, Pattern::Expression(expr)))
61}
62
63#[derive(Clone)]
64enum PatternArrayToken {
65 Spread,
66 Pipe,
67 Item(Pattern),
68}
69
70fn pattern_array_token(input: ParseString) -> ParseResult<PatternArrayToken> {
71 if let Ok((input, _)) = spread_operator(input.clone()) {
72 return Ok((input, PatternArrayToken::Spread));
73 }
74 if let Ok((input, _)) = enum_separator(input.clone()) {
75 return Ok((input, PatternArrayToken::Pipe));
76 }
77 let (input, item) = pattern_array_item(input)?;
78 Ok((input, PatternArrayToken::Item(item)))
79}
80
81pub fn pattern_array(input: ParseString) -> ParseResult<PatternArray> {
83 let (mut input, _) = left_bracket(input)?;
84 let (next_input, _) = whitespace0(input)?;
85 input = next_input;
86
87 let mut tokens = Vec::new();
88 loop {
89 if let Ok((next_input, _)) = right_bracket(input.clone()) {
90 input = next_input;
91 break;
92 }
93
94 let (next_input, token) = pattern_array_token(input.clone())?;
95 input = next_input;
96 tokens.push(token);
97
98 let (next_input, _) = whitespace0(input)?;
99 input = next_input;
100 if let Ok((next_input, _)) = list_separator(input.clone()) {
101 input = next_input;
102 continue;
103 }
104 }
105
106 let pipe_positions = tokens
107 .iter()
108 .enumerate()
109 .filter_map(|(ix, token)| match token {
110 PatternArrayToken::Pipe => Some(ix),
111 _ => None,
112 })
113 .collect::<Vec<usize>>();
114
115 if pipe_positions.len() > 1 {
116 return Err(nom::Err::Error(ParseError::new(
117 input,
118 "Only one | rest binding is allowed in an array pattern",
119 )));
120 }
121
122 if let Some(pipe_ix) = pipe_positions.first().copied() {
123 if tokens.iter().any(|token| matches!(token, PatternArrayToken::Spread)) {
124 return Err(nom::Err::Error(ParseError::new(
125 input,
126 "Cannot mix ... spread and | rest binding in an array pattern",
127 )));
128 }
129
130 let mut prefix = vec![];
131 for token in tokens[..pipe_ix].iter() {
132 match token {
133 PatternArrayToken::Item(pattern) => prefix.push(pattern.clone()),
134 _ => {
135 return Err(nom::Err::Error(ParseError::new(
136 input.clone(),
137 "Only patterns are allowed before | in an array pattern",
138 )));
139 }
140 }
141 }
142
143 let rest_tokens = &tokens[pipe_ix + 1..];
144 if rest_tokens.len() != 1 {
145 return Err(nom::Err::Error(ParseError::new(
146 input,
147 "Array rest binding must be exactly one pattern after |",
148 )));
149 }
150
151 let binding = match &rest_tokens[0] {
152 PatternArrayToken::Item(pattern) => pattern.clone(),
153 _ => {
154 return Err(nom::Err::Error(ParseError::new(
155 input,
156 "Array rest binding must be a pattern after |",
157 )));
158 }
159 };
160
161 return Ok((
162 input,
163 PatternArray {
164 prefix,
165 spread: Some(PatternArraySpread {
166 binding: Some(Box::new(binding)),
167 }),
168 suffix: vec![],
169 },
170 ));
171 }
172
173 let spread_positions = tokens
174 .iter()
175 .enumerate()
176 .filter_map(|(ix, token)| match token {
177 PatternArrayToken::Spread => Some(ix),
178 _ => None,
179 })
180 .collect::<Vec<usize>>();
181
182 if spread_positions.len() > 1 {
183 return Err(nom::Err::Error(ParseError::new(
184 input,
185 "Only one spread operator is allowed in an array pattern",
186 )));
187 }
188
189 let spread_ix = spread_positions.first().copied();
190 let mut prefix = vec![];
191 let mut suffix = vec![];
192
193 if let Some(ix) = spread_ix {
194 prefix = tokens[..ix]
195 .iter()
196 .filter_map(|token| match token {
197 PatternArrayToken::Item(pattern) => Some(pattern.clone()),
198 _ => None,
199 })
200 .collect();
201 suffix = tokens[ix + 1..]
202 .iter()
203 .filter_map(|token| match token {
204 PatternArrayToken::Item(pattern) => Some(pattern.clone()),
205 _ => None,
206 })
207 .collect();
208 } else {
209 prefix = tokens
210 .iter()
211 .filter_map(|token| match token {
212 PatternArrayToken::Item(pattern) => Some(pattern.clone()),
213 _ => None,
214 })
215 .collect();
216 }
217
218 let spread = spread_ix.map(|_| {
219 let prefix_ends_wildcard = matches!(prefix.last(), Some(Pattern::Wildcard));
220 let mut spread_binding: Option<Box<Pattern>> = None;
221 if prefix_ends_wildcard {
222 if suffix.len() == 1 {
223 spread_binding = suffix.pop().map(Box::new);
224 } else if suffix.len() >= 2 {
225 spread_binding = Some(Box::new(suffix.remove(0)));
226 }
227 }
228 PatternArraySpread { binding: spread_binding }
229 });
230
231 Ok((input, PatternArray { prefix, spread, suffix }))
232}
233
234pub fn pattern_atom_struct(input: ParseString) -> ParseResult<PatternTupleStruct> {
236 let (input, _) = colon(input)?;
237 let (input, id) = identifier(input)?;
238 let (input, _) = left_parenthesis(input)?;
239 let (input, _) = whitespace0(input)?;
240 let (input, patterns) = separated_list1(list_separator, pattern)(input)?;
241 let (input, _) = whitespace0(input)?;
242 let (input, _) = right_parenthesis(input)?;
243 Ok((input, PatternTupleStruct{name: id, patterns}))
244}
245
246pub fn pattern_tuple(input: ParseString) -> ParseResult<PatternTuple> {
248 let (input, _) = left_parenthesis(input)?;
249 let (input, _) = whitespace0(input)?;
250 let (input, patterns) = separated_list1(list_separator, pattern)(input)?;
251 let (input, _) = whitespace0(input)?;
252 let (input, _) = right_parenthesis(input)?;
253 Ok((input, PatternTuple(patterns)))
254}