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