Skip to main content

rustidy_ast/
pat.rs

1//! Patterns
2
3// Modules
4pub mod range;
5
6// Exports
7pub use self::range::RangePattern;
8
9// Imports
10use {
11	crate::{attr, util::FmtSingleOrIndent},
12	super::{
13		attr::WithOuterAttributes,
14		expr::{
15			MacroInvocation,
16			PathExpression,
17			without_block::{TupleIndex, path::PathInExpression},
18		},
19		token,
20		util::{Braced, Bracketed, Parenthesized},
21	},
22	core::fmt::Debug,
23	rustidy_ast_literal::{ByteLiteral, ByteStringLiteral, LiteralExpression},
24	rustidy_ast_util::{
25		AtLeast1,
26		Identifier,
27		Punctuated,
28		PunctuatedTrailing,
29		at_least,
30		delimited,
31		punct,
32	},
33	rustidy_format::{Format, Formattable, WhitespaceFormat},
34	rustidy_parse::{Parse, ParsePeeked, ParserError},
35	rustidy_print::Print,
36	rustidy_util::Whitespace,
37};
38
39/// `Pattern`
40#[derive(PartialEq, Eq, Clone, Debug)]
41#[derive(serde::Serialize, serde::Deserialize)]
42#[derive(Parse, Formattable, Format, Print)]
43#[parse(name = "a pattern")]
44pub struct Pattern {
45	pub top_alt: Option<token::Or>,
46	#[format(prefix_ws(expr = Whitespace::SINGLE, if_ = self.top_alt.is_some()))]
47	#[format(args = punct::fmt(Whitespace::SINGLE, Whitespace::SINGLE))]
48	pub inner:   Punctuated<PatternNoTopAlt, token::Or>,
49}
50
51/// `PatternNoTopAlt`
52#[derive(PartialEq, Eq, Clone, Debug)]
53#[derive(serde::Serialize, serde::Deserialize)]
54#[derive(Parse, Formattable, Format, Print)]
55pub enum PatternNoTopAlt {
56	Range(RangePattern),
57	WithoutRange(PatternWithoutRange),
58}
59
60/// `PatternWithoutRange`
61#[derive(PartialEq, Eq, Clone, Debug)]
62#[derive(serde::Serialize, serde::Deserialize)]
63#[derive(Parse, Formattable, Format, Print)]
64pub enum PatternWithoutRange {
65	Struct(StructPattern),
66	TupleStruct(TupleStructPattern),
67	Path(PathPattern),
68
69	#[parse(peek = ByteLiteral)]
70	#[parse(peek = ByteStringLiteral)]
71	Literal(LiteralPattern),
72	// TODO: Parse this for single identifiers too?
73	#[parse(peek = (Option::<token::Ref>, Option::<token::Mut>, Identifier, token::At))]
74	Ident(IdentifierPattern),
75	Wildcard(WildcardPattern),
76	Rest(RestPattern),
77	Reference(ReferencePattern),
78	Tuple(TuplePattern),
79	Grouped(GroupedPattern),
80	Slice(SlicePattern),
81
82	#[parse(peek = MacroInvocation)]
83	Macro(MacroInvocation),
84}
85
86/// `WildcardPattern`
87#[derive(PartialEq, Eq, Clone, Debug)]
88#[derive(serde::Serialize, serde::Deserialize)]
89#[derive(Parse, Formattable, Format, Print)]
90pub struct WildcardPattern(token::Underscore);
91
92/// `RestPattern`
93#[derive(PartialEq, Eq, Clone, Debug)]
94#[derive(serde::Serialize, serde::Deserialize)]
95#[derive(Parse, Formattable, Format, Print)]
96pub struct RestPattern(token::DotDot);
97
98/// `GroupedPattern`
99#[derive(PartialEq, Eq, Clone, Debug)]
100#[derive(serde::Serialize, serde::Deserialize)]
101#[derive(Parse, Formattable, Format, Print)]
102pub struct GroupedPattern(#[format(args = delimited::FmtRemove)] Parenthesized<Box<Pattern>>);
103
104/// `SlicePattern`
105#[derive(PartialEq, Eq, Clone, Debug)]
106#[derive(serde::Serialize, serde::Deserialize)]
107#[derive(Parse, Formattable, Format, Print)]
108pub struct SlicePattern(#[format(args = delimited::FmtRemove)] Bracketed<Option<SlicePatternItems>>);
109
110/// `SlicePatternItems`
111#[derive(PartialEq, Eq, Clone, Debug)]
112#[derive(serde::Serialize, serde::Deserialize)]
113#[derive(Parse, Formattable, Format, Print)]
114pub struct SlicePatternItems(
115	#[format(args = punct::fmt(Whitespace::SINGLE, Whitespace::REMOVE))]
116	PunctuatedTrailing<Box<Pattern>, token::Comma>,
117);
118
119/// `PathPattern`
120#[derive(PartialEq, Eq, Clone, Debug)]
121#[derive(serde::Serialize, serde::Deserialize)]
122#[derive(Parse, Formattable, Format, Print)]
123pub struct PathPattern(PathExpression);
124
125/// `ReferencePattern`
126#[derive(PartialEq, Eq, Clone, Debug)]
127#[derive(serde::Serialize, serde::Deserialize)]
128#[derive(Parse, Formattable, Format, Print)]
129pub struct ReferencePattern {
130	pub ref_: ReferencePatternRef,
131	#[format(prefix_ws = Whitespace::REMOVE)]
132	pub mut_: Option<token::Mut>,
133	#[format(prefix_ws = match self.mut_.is_some() {
134		true => Whitespace::SINGLE,
135		false => Whitespace::REMOVE,
136	})]
137	pub pat:  Box<PatternWithoutRange>,
138}
139
140#[derive(PartialEq, Eq, Clone, Debug)]
141#[derive(serde::Serialize, serde::Deserialize)]
142#[derive(Parse, Formattable, Format, Print)]
143pub enum ReferencePatternRef {
144	And(token::And),
145	AndAnd(token::AndAnd),
146}
147
148/// `StructPattern`
149#[derive(PartialEq, Eq, Clone, Debug)]
150#[derive(serde::Serialize, serde::Deserialize)]
151#[derive(Parse, Formattable, Format, Print)]
152pub struct StructPattern {
153	pub top:   PathInExpression,
154	#[format(prefix_ws = Whitespace::SINGLE)]
155	#[format(args = delimited::fmt_single_or_indent_if_non_blank(
156		50,
157		FmtSingleOrIndent::Single,
158		FmtSingleOrIndent::Indent
159	))]
160	pub items: Braced<Option<StructPatternElements>>,
161}
162
163/// `StructPatternElements`
164#[derive(PartialEq, Eq, Clone, Debug)]
165#[derive(serde::Serialize, serde::Deserialize)]
166#[derive(Parse, Formattable, Format, Print)]
167#[format(args(ty = "FmtSingleOrIndent"))]
168pub enum StructPatternElements {
169	#[format(args = args)]
170	Fields(StructPatternElementsFields),
171	EtCetera(StructPatternEtCetera),
172}
173
174#[derive(PartialEq, Eq, Clone, Debug)]
175#[derive(serde::Serialize, serde::Deserialize)]
176#[derive(Parse, Formattable, Format, Print)]
177#[format(args(ty = "FmtSingleOrIndent"))]
178pub struct StructPatternElementsFields {
179	#[format(args = args)]
180	pub fields:    StructPatternFields,
181	#[format(prefix_ws = Whitespace::REMOVE)]
182	#[format(args = args)]
183	pub et_cetera: Option<StructPatternElementsFieldsEtCetera>,
184}
185
186#[derive(PartialEq, Eq, Clone, Debug)]
187#[derive(serde::Serialize, serde::Deserialize)]
188#[derive(Parse, Formattable, Format, Print)]
189#[format(args(ty = "FmtSingleOrIndent"))]
190pub struct StructPatternElementsFieldsEtCetera {
191	pub comma:     token::Comma,
192	#[format(prefix_ws = args.prefix_ws())]
193	pub et_cetera: Option<StructPatternEtCetera>,
194}
195
196/// `StructPatternFields`
197#[derive(PartialEq, Eq, Clone, Debug)]
198#[derive(serde::Serialize, serde::Deserialize)]
199#[derive(Parse, Formattable, Format, Print)]
200#[format(args(ty = "FmtSingleOrIndent"))]
201pub struct StructPatternFields(
202	#[format(args = punct::fmt(args.prefix_ws(), Whitespace::REMOVE))]
203	Punctuated<StructPatternField, token::Comma>,
204);
205
206/// `StructPatternField`
207#[derive(PartialEq, Eq, Clone, Debug)]
208#[derive(serde::Serialize, serde::Deserialize)]
209#[derive(Parse, Formattable, Format, Print)]
210pub struct StructPatternField(
211	#[format(args = attr::with::fmt(Whitespace::INDENT))]
212	pub WithOuterAttributes<StructPatternFieldInner>,
213);
214
215#[derive(PartialEq, Eq, Clone, Debug)]
216#[derive(serde::Serialize, serde::Deserialize)]
217#[derive(Parse, Formattable, Format, Print)]
218pub enum StructPatternFieldInner {
219	TuplePat(StructPatternFieldTuplePat),
220	IdentPat(StructPatternFieldIdentPat),
221	Ident(StructPatternFieldIdent),
222}
223
224#[derive(PartialEq, Eq, Clone, Debug)]
225#[derive(serde::Serialize, serde::Deserialize)]
226#[derive(Parse, Formattable, Format, Print)]
227pub struct StructPatternFieldTuplePat {
228	pub idx: TupleIndex,
229	#[format(prefix_ws = Whitespace::REMOVE)]
230	pub dot: token::Colon,
231	#[format(prefix_ws = Whitespace::SINGLE)]
232	pub pat: Box<Pattern>,
233}
234
235#[derive(PartialEq, Eq, Clone, Debug)]
236#[derive(serde::Serialize, serde::Deserialize)]
237#[derive(Parse, Formattable, Format, Print)]
238pub struct StructPatternFieldIdentPat {
239	pub ident: Identifier,
240	#[format(prefix_ws = Whitespace::REMOVE)]
241	pub dot:   token::Colon,
242	#[format(prefix_ws = Whitespace::SINGLE)]
243	pub pat:   Box<Pattern>,
244}
245
246#[derive(PartialEq, Eq, Clone, Debug)]
247#[derive(serde::Serialize, serde::Deserialize)]
248#[derive(Parse, Formattable, Format, Print)]
249pub struct StructPatternFieldIdent {
250	pub ref_:  Option<token::Ref>,
251	#[format(prefix_ws(expr = Whitespace::SINGLE, if_ = self.ref_.is_some()))]
252	pub mut_:  Option<token::Mut>,
253	#[format(prefix_ws(expr = Whitespace::SINGLE, if_ = self.ref_.is_some() || self.mut_.is_some()))]
254	pub ident: Identifier,
255}
256
257/// `StructPatternEtCetera`
258#[derive(PartialEq, Eq, Clone, Debug)]
259#[derive(serde::Serialize, serde::Deserialize)]
260#[derive(Parse, Formattable, Format, Print)]
261pub struct StructPatternEtCetera(token::DotDot);
262
263/// `TupleStructPattern`
264#[derive(PartialEq, Eq, Clone, Debug)]
265#[derive(serde::Serialize, serde::Deserialize)]
266#[derive(Parse, Formattable, Format, Print)]
267pub struct TupleStructPattern {
268	pub top:   PathInExpression,
269	#[format(prefix_ws = Whitespace::REMOVE)]
270	#[format(args = delimited::FmtRemove)]
271	pub items: Parenthesized<Option<TupleStructItems>>,
272}
273
274/// `TupleStructItems`
275#[derive(PartialEq, Eq, Clone, Debug)]
276#[derive(serde::Serialize, serde::Deserialize)]
277#[derive(Parse, Formattable, Format, Print)]
278pub struct TupleStructItems(
279	#[format(args = punct::fmt(Whitespace::SINGLE, Whitespace::REMOVE))]
280	pub PunctuatedTrailing<Box<Pattern>, token::Comma>,
281);
282
283/// `TuplePattern`
284#[derive(PartialEq, Eq, Clone, Debug)]
285#[derive(serde::Serialize, serde::Deserialize)]
286#[derive(Parse, Formattable, Format, Print)]
287pub struct TuplePattern(
288	#[format(args = delimited::FmtRemove)]
289	Parenthesized<Option<TuplePatternItems>>,
290);
291
292/// `TuplePatternItems`
293#[derive(PartialEq, Eq, Clone, Debug)]
294#[derive(serde::Serialize, serde::Deserialize)]
295#[derive(Parse, Formattable, Format, Print)]
296pub enum TuplePatternItems {
297	Pats(TupleItemsPats),
298	Pat(TupleItemsPat),
299	Rest(RestPattern),
300}
301
302#[derive(PartialEq, Eq, Clone, Debug)]
303#[derive(serde::Serialize, serde::Deserialize)]
304#[derive(Parse, Formattable, Format, Print)]
305pub struct TupleItemsPat {
306	pub pat:   Box<Pattern>,
307	#[format(prefix_ws = Whitespace::REMOVE)]
308	pub comma: token::Comma,
309}
310
311#[derive(PartialEq, Eq, Clone, Debug)]
312#[derive(serde::Serialize, serde::Deserialize)]
313#[derive(Parse, Formattable, Format, Print)]
314pub struct TupleItemsPats {
315	pub first:          Box<Pattern>,
316	#[format(prefix_ws = Whitespace::REMOVE)]
317	#[format(args = at_least::fmt_prefix_ws(Whitespace::REMOVE))]
318	pub rest:           AtLeast1<TupleItemsPatsPat>,
319	#[format(prefix_ws = Whitespace::REMOVE)]
320	pub trailing_comma: Option<token::Comma>,
321}
322
323#[derive(PartialEq, Eq, Clone, Debug)]
324#[derive(serde::Serialize, serde::Deserialize)]
325#[derive(Parse, Formattable, Format, Print)]
326pub struct TupleItemsPatsPat {
327	pub comma: token::Comma,
328	#[format(prefix_ws = Whitespace::SINGLE)]
329	pub pat:   Box<Pattern>,
330}
331
332/// `LiteralPattern`
333#[derive(PartialEq, Eq, Clone, Debug)]
334#[derive(serde::Serialize, serde::Deserialize)]
335#[derive(Parse, Formattable, Format, Print)]
336pub struct LiteralPattern {
337	pub minus:   Option<token::Minus>,
338	pub literal: LiteralExpression,
339}
340
341impl ParsePeeked<ByteLiteral> for LiteralPattern {
342	fn parse_from_with_peeked(_parser: &mut rustidy_parse::Parser, parsed: ByteLiteral) -> Result<Self, Self::Error> {
343		Ok(Self {
344			minus: None,
345			literal: LiteralExpression::Byte(parsed),
346		})
347	}
348}
349
350impl ParsePeeked<ByteStringLiteral> for LiteralPattern {
351	fn parse_from_with_peeked(
352		_parser: &mut rustidy_parse::Parser,
353		parsed: ByteStringLiteral
354	) -> Result<Self, Self::Error> {
355		Ok(Self {
356			minus: None,
357			literal: LiteralExpression::ByteString(parsed),
358		})
359	}
360}
361
362/// `IdentifierPattern`
363#[derive(PartialEq, Eq, Clone, Debug)]
364#[derive(serde::Serialize, serde::Deserialize)]
365#[derive(Parse, Formattable, Format, Print)]
366#[parse(error(name = Pat(ParserError::<PatternNoTopAlt>), transparent))]
367pub struct IdentifierPattern {
368	pub ref_:  Option<token::Ref>,
369	#[format(prefix_ws(expr = Whitespace::SINGLE, if_ = self.ref_.is_some()))]
370	pub mut_:  Option<token::Mut>,
371	#[format(prefix_ws(expr = Whitespace::SINGLE, if_ = self.ref_.is_some() || self.mut_.is_some()))]
372	pub ident: Identifier,
373	#[format(prefix_ws = Whitespace::SINGLE)]
374	pub rest:  Option<IdentifierPatternRest>,
375}
376
377impl ParsePeeked<(Option<token::Ref>, Option<token::Mut>, Identifier, token::At)> for IdentifierPattern {
378	fn parse_from_with_peeked(
379		parser: &mut rustidy_parse::Parser,
380		(ref_, mut_, ident, at): (Option<token::Ref>, Option<token::Mut>, Identifier, token::At),
381	) -> Result<Self, Self::Error> {
382		let pat = parser
383			.parse::<PatternNoTopAlt>()
384			.map_err(Self::Error::Pat)?;
385		Ok(Self {
386			ref_,
387			mut_,
388			ident,
389			rest: Some(IdentifierPatternRest { at, pat: Box::new(pat) }),
390		})
391	}
392}
393
394#[derive(PartialEq, Eq, Clone, Debug)]
395#[derive(serde::Serialize, serde::Deserialize)]
396#[derive(Parse, Formattable, Format, Print)]
397pub struct IdentifierPatternRest {
398	pub at:  token::At,
399	#[format(prefix_ws = Whitespace::SINGLE)]
400	pub pat: Box<PatternNoTopAlt>,
401}